Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : /**
3 : * @file tensor_base.h
4 : * @date 01 December 2023
5 : * @brief This is Tensor base class
6 : * @see https://github.com/nnstreamer/nntrainer
7 : * @author Jijoong Moon <jijoong.moon@samsung.com>
8 : * @author Donghyeon Jeong <dhyeon.jeong@samsung.com>
9 : * @bug No known bugs except for NYI items
10 : */
11 :
12 : #ifndef __TENSOR_BASE_H__
13 : #define __TENSOR_BASE_H__
14 : #ifdef __cplusplus
15 :
16 : #include <memory>
17 : #include <stdexcept>
18 :
19 : #include <memory_data.h>
20 : #include <nntrainer_error.h>
21 : #include <quantizer.h>
22 : #include <tensor_dim.h>
23 : #include <util_func.h>
24 :
25 : #define transposeloop(cl, ci, cj, ck, sl, si, sj, sk) \
26 : do { \
27 : unsigned int i, j, k, l; \
28 : int inidx = 0, outidx = 0; \
29 : for (cl = 0; cl < sl; cl++) \
30 : for (ci = 0; ci < si; ci++) \
31 : for (cj = 0; cj < sj; cj++) \
32 : for (ck = 0; ck < sk; ck++) { \
33 : outidx = si * sj * sk * cl + sj * sk * ci + sk * cj + ck; \
34 : inidx = l * SI * SJ * SK + i * SJ * SK + j * SK + k; \
35 : outptr[outidx] = inptr[inidx]; \
36 : } \
37 : } while (0);
38 :
39 : #define transposeloop_nhwc(cl, ci, cj, ck, sl, si, sj, sk) \
40 : do { \
41 : unsigned int i, j, k, l; \
42 : int inidx = 0, outidx = 0; \
43 : for (cl = 0; cl < sl; cl++) \
44 : for (ci = 0; ci < si; ci++) \
45 : for (cj = 0; cj < sj; cj++) \
46 : for (ck = 0; ck < sk; ck++) { \
47 : outidx = si * sj * sk * cl + sj * sk * ci + sk * cj + ck; \
48 : inidx = l * SJ * SK * SI + j * SK * SI + k * SI + i; \
49 : outptr[outidx] = inptr[inidx]; \
50 : } \
51 : } while (0);
52 :
53 : namespace nntrainer {
54 :
55 : using TensorDim = ml::train::TensorDim;
56 : using Tformat = ml::train::TensorDim::Format;
57 : using Tdatatype = ml::train::TensorDim::DataType;
58 : using TStorageOrder = ml::train::TensorDim::StorageOrder;
59 :
60 : /**
61 : * @brief Enumeration of Weight Initialization Type
62 : * @todo support intialization from file
63 : */
64 : enum class Initializer {
65 : ZEROS, /** Zero initialization */
66 : ONES, /** One initialization */
67 : LECUN_NORMAL, /** LeCun normal initialization */
68 : LECUN_UNIFORM, /** uniform initialization */
69 : XAVIER_NORMAL, /** Xavier normal initialization */
70 : XAVIER_UNIFORM, /** Xavier uniform initialization */
71 : HE_NORMAL, /** He normal initialization */
72 : HE_UNIFORM, /** He uniform initialization */
73 : NONE /** No initialization */
74 : };
75 :
76 : class Tensor;
77 : class SrcSharedTensorBase;
78 :
79 : /**
80 : * @class TensorBase class
81 : * @brief TensorBase is an abstract class that provides a base for various
82 : * tensor classes with different data types such as FloatTensor to extend and
83 : * implement abstract methods.
84 : *
85 : * @note Basic functions required for tensor memory allocation and data
86 : * modification, such as allocate(), getData(), and setValue(), are necessary
87 : * when creating subclasses (new tensor class).
88 : *
89 : * The remaining operations that are used for mathematical operations are not
90 : * essential to create a new tensor class but later should be implemented in a
91 : * child class in order to utilize its tensor operations fully.
92 : */
93 : class TensorBase {
94 : public:
95 : /**
96 : * @brief Basic Constructor of Tensor
97 : */
98 658324 : TensorBase(std::string name_ = "", Tformat fm = Tformat::NCHW,
99 658324 : Tdatatype d_type = Tdatatype::FP32) :
100 1316648 : dim(TensorDim(fm, d_type)),
101 658324 : strides(dim.computeStrides()),
102 658324 : contiguous(true),
103 658324 : initializer(Initializer::NONE),
104 658324 : name(name_),
105 : data(nullptr),
106 658324 : offset(0),
107 658324 : file_offset(0),
108 658324 : src_tensor() {}
109 :
110 : /**
111 : * @brief Constructor of Tensor with dimension, possibly lazily
112 : * @param d Tensor dim for this tensor
113 : * @param alloc_now If the memory of the tensor must be allocated
114 : * @param init Initializer for the tensor
115 : * @param name Name of the tensor
116 : */
117 : TensorBase(const TensorDim &d, bool alloc_now,
118 : Initializer init = Initializer::NONE, std::string name = "");
119 :
120 : /**
121 : * @brief Constructor of Tensor with dimension/buf
122 : * @param d Tensor dim for this tensor
123 : * @param buf buffer
124 : * @note Memory for this tensor is instantaneously allocated
125 : */
126 : TensorBase(const TensorDim &d, const void *buf = nullptr) :
127 : TensorBase(d, true) {}
128 :
129 : /**
130 : * @brief Copy constructor of TensorBase.
131 : * @param[in] Tensor &
132 : */
133 540310 : TensorBase(const TensorBase &rhs) {
134 540310 : dim = rhs.dim;
135 540310 : strides = rhs.strides;
136 540310 : contiguous = rhs.contiguous;
137 540310 : initializer = rhs.initializer;
138 540310 : name = rhs.name;
139 : data = rhs.data;
140 540310 : offset = rhs.offset;
141 540310 : file_offset = rhs.file_offset;
142 : src_tensor = rhs.src_tensor;
143 540310 : }
144 :
145 : /**
146 : * @brief Comparison operator overload
147 : * @param[in] rhs Tensor to be compared with
148 : * @note Only compares Tensor information
149 : */
150 : bool operator==(const TensorBase &rhs) const;
151 :
152 : /**
153 : * @brief Comparison operator overload
154 : * @param[in] rhs Tensor to be compared with
155 : * @note Only compares Tensor information
156 : */
157 : bool operator!=(const TensorBase &rhs) const { return !(*this == rhs); }
158 :
159 : /**
160 : * @copydoc Tensor::setTensorVar(TensorDim d, void *buf, size_t offset)
161 : */
162 : void setTensorVar(TensorDim d, void *buf, size_t offset);
163 :
164 : /**
165 : * @brief Basic Destructor
166 : */
167 2397068 : virtual ~TensorBase() {}
168 :
169 : /**
170 : * @copydoc Tensor::allocate()
171 : */
172 : virtual void allocate() = 0;
173 :
174 : /**
175 : * @copydoc Tensor::deallocate()
176 : */
177 : virtual void deallocate() = 0;
178 :
179 : /**
180 : * @copydoc Tensor::isAllocated()
181 : */
182 : bool isAllocated() { return data != nullptr; }
183 :
184 : /**
185 : * @brief activate function with the given pointer address
186 : * @note This should be called for virtual tensor only.
187 : */
188 0 : void activate(void *addr) {
189 0 : data = std::shared_ptr<MemoryData>(new MemoryData((void *)addr));
190 0 : }
191 :
192 : /**
193 : * @brief deactivate
194 : * @note This should be called for virtual tensor only.
195 : */
196 0 : void deactivate() {
197 : data.reset();
198 : data = nullptr;
199 0 : }
200 :
201 : /**
202 : * @copydoc Tensor::getData()
203 : */
204 : virtual void *getData() const = 0;
205 :
206 : /**
207 : * @copydoc Tensor::getData(size_t idx)
208 : */
209 : virtual void *getData(size_t idx) const = 0;
210 :
211 : /**
212 : * @copydoc Tensor::getScale()
213 : */
214 1 : virtual void *getScale() const {
215 : throw std::invalid_argument(
216 1 : "Tensor::getScale() is not supported in tensor data type " +
217 3 : getStringDataType());
218 : }
219 :
220 : /**
221 : * @copydoc Tensor::getScale(size_t idx)
222 : */
223 0 : virtual void *getScale(size_t idx) const {
224 : throw std::invalid_argument(
225 0 : "Tensor::getScale() is not supported in tensor data type " +
226 0 : getStringDataType());
227 : }
228 :
229 : /**
230 : * @copydoc Tensor::getZeroPoint()
231 : */
232 0 : virtual unsigned int *getZeroPoint() const {
233 : throw std::invalid_argument(
234 0 : "Tensor::getZeroPoint() is not supported in tensor data type " +
235 0 : getStringDataType());
236 : }
237 :
238 : /**
239 : * @copydoc Tensor::getZeroPoint(size_t idx)
240 : */
241 0 : virtual unsigned int *getZeroPoint(size_t idx) const {
242 : throw std::invalid_argument(
243 0 : "Tensor::getZeroPoint() is not supported in tensor data type " +
244 0 : getStringDataType());
245 : }
246 :
247 : /**
248 : * @brief i data index
249 : * @retval address of ith data
250 : */
251 : virtual void *getAddress(unsigned int i) = 0;
252 :
253 : /**
254 : * @brief i data index
255 : * @retval address of ith data
256 : */
257 : virtual const void *getAddress(unsigned int i) const = 0;
258 :
259 : /**
260 : * @copydoc Tensor::setValue(float value)
261 : */
262 : virtual void setValue(float value) = 0;
263 :
264 : /**
265 : * @copydoc Tensor::setValue(b, c, h, w, value)
266 : */
267 : virtual void setValue(unsigned int b, unsigned int c, unsigned int h,
268 : unsigned int w, float value) = 0;
269 :
270 : /**
271 : * @copydoc Tensor::addValue()
272 : */
273 : virtual void addValue(unsigned int b, unsigned int c, unsigned int h,
274 : unsigned int w, float value, float beta) = 0;
275 :
276 : /**
277 : * @copydoc Tensor::setZero()
278 : */
279 : virtual void setZero() = 0;
280 :
281 : /**
282 : * @copydoc Tensor::setRandNormal()
283 : */
284 : virtual void setRandNormal(float mean, float stddev);
285 :
286 : /**
287 : * @copydoc Tensor::setRandBernoulli()
288 : */
289 : virtual void setRandUniform(float min, float max);
290 :
291 : /**
292 : * @copydoc Tensor::setRandBernoulli()
293 : */
294 : virtual void setRandBernoulli(float probability);
295 :
296 : /**
297 : * @copydoc Tensor::initialize()
298 : */
299 : virtual void initialize() = 0;
300 :
301 : /**
302 : * @copydoc Tensor::initialize(Initializer init)
303 : */
304 : virtual void initialize(Initializer init) = 0;
305 :
306 : /**
307 : * @copydoc Tensor::multiply_strided(Tensor const &m, Tensor &output,
308 : * const float beta)
309 : */
310 : virtual Tensor multiply_strided(Tensor const &m, Tensor &output,
311 : const float beta) const;
312 :
313 : /**
314 : * @copydoc Tensor::multiply_i(float const &value)
315 : */
316 : virtual int multiply_i(float const &value);
317 :
318 : /**
319 : * @copydoc Tensor::multiply(float const &value, Tensor &output)
320 : */
321 : virtual Tensor &multiply(float const &value, Tensor &output) const;
322 :
323 : /**
324 : * @copydoc Tensor::multiply(Tensor const &m, Tensor &output, const
325 : * float beta = 0.0)
326 : */
327 : virtual Tensor &multiply(Tensor const &m, Tensor &output,
328 : const float beta = 0.0) const;
329 :
330 : /**
331 : * @copydoc Tensor::divide(float const &value, Tensor &output)
332 : */
333 : virtual Tensor ÷(float const &value, Tensor &output) const;
334 :
335 : /**
336 : * @copydoc Tensor::divide(Tensor const &m, Tensor &output)
337 : */
338 : virtual Tensor ÷(Tensor const &m, Tensor &output) const;
339 :
340 : /**
341 : * @copydoc Tensor::add_strided(Tensor const &input, Tensor &output,
342 : * const float beta)
343 : */
344 : virtual Tensor &add_strided(Tensor const &input, Tensor &output,
345 : const float beta) const;
346 :
347 : /**
348 : * @copydoc Tensor::add_i_partial()
349 : */
350 : virtual int add_i_partial(unsigned int len, unsigned int addr_idx, Tensor &m,
351 : unsigned int incX, unsigned int incY,
352 : const Tensor alphas, unsigned int alpha_idx);
353 :
354 : /**
355 : * @copydoc Tensor::add(float const &value, Tensor &output)
356 : */
357 : virtual Tensor &add(float const &value, Tensor &output) const;
358 :
359 : /**
360 : * @copydoc Tensor::add(Tensor const &m, Tensor &output, float const
361 : * alpha)
362 : */
363 : virtual Tensor &add(Tensor const &m, Tensor &output, float const alpha) const;
364 :
365 : /**
366 : * @copydoc Tensor::subtract(float const &value, Tensor &output)
367 : */
368 : virtual Tensor &subtract(float const &value, Tensor &output) const;
369 :
370 : /**
371 : * @brief Sum all the Tensor elements according to the batch
372 : * @param[out] output Tensor(batch, 1, 1, 1)
373 : */
374 : virtual void sum_by_batch(Tensor &output) const;
375 :
376 : /**
377 : * @copydoc Tensor::sum(unsigned int axis, Tensor &output, float alpha,
378 : * float beta) const
379 : */
380 : virtual Tensor &sum(unsigned int axis, Tensor &output, float alpha,
381 : float beta) const;
382 :
383 : /**
384 : * @copydoc Tensor::abs()
385 : */
386 : virtual Tensor &abs(Tensor &output) const;
387 :
388 : /**
389 : * @copydoc Tensor::l2norm
390 : */
391 : virtual float l2norm() const;
392 :
393 : /**
394 : * @copydoc Tensor::pow(float exponent, Tensor &output)
395 : */
396 : virtual Tensor &pow(float exponent, Tensor &output) const;
397 :
398 : /**
399 : * @copydoc Tensor::sqrt(Tensor &output)
400 : */
401 : virtual Tensor &sqrt(Tensor &output) const;
402 :
403 : /**
404 : * @copydoc Tensor::erf(Tensor &output)
405 : */
406 : virtual Tensor &erf(Tensor &output) const;
407 :
408 : /**
409 : * @brief sin transform function
410 : * @param[out] out out to store the result
411 : */
412 : virtual void sin(Tensor &out, float alpha = 1.0);
413 :
414 : /**
415 : * @brief cos transform function
416 : * @param[out] out out to store the result
417 : */
418 : virtual void cos(Tensor &out, float alpha = 1.0);
419 :
420 : /**
421 : * @brief tangent transform function
422 : * @param[out] output output to store the result
423 : */
424 : virtual void tan(Tensor &output, float alpha = 1.0);
425 :
426 : /**
427 : * @brief inverse squared root function
428 : * @param[out] out out to store the result
429 : */
430 : virtual void inv_sqrt(Tensor &out);
431 :
432 : /**
433 : * @brief Dot Product of Tensor ( equal MxM )
434 : * @details This applies dot of the last dimension of this and
435 : * second-last dimension of passed tensor m.
436 : * @param[in] input Tensor
437 : * @param[in] output output Tensor
438 : * @param[in] trans Transpose
439 : * @param[in] trans_in Transpose input
440 : * @param[in] beta beta
441 : * @retval Calculated Tensor
442 : */
443 : virtual Tensor &dot(Tensor const &input, Tensor &output, bool trans,
444 : bool trans_in, float beta) const;
445 :
446 : /**
447 : * @brief Dot Product of Tensors ( equal MxMs )
448 : * @details This applies dot of the last dimension of this and
449 : * second-last dimension of passed tensor m.
450 : * @param[in] input Tensor
451 : * @param[in] output output Tensors
452 : * @param[in] trans Transpose
453 : * @param[in] trans_in Transpose input
454 : * @param[in] beta beta
455 : * @retval Calculated Tensor
456 : */
457 : virtual void dot(std::vector<Tensor *> input, std::vector<Tensor *> output,
458 : bool trans, bool trans_in, float beta) const;
459 :
460 : /**
461 : * @copydoc Tensor::dropout_mask(float dropout)
462 : */
463 : virtual void dropout_mask(float dropout);
464 :
465 : /**
466 : * @copydoc Tensor::filter_mask(const Tensor &mask_len, bool reverse)
467 : */
468 : virtual void filter_mask(const Tensor &mask_len, bool reverse);
469 :
470 : /**
471 : * @copydoc Tensor::zoneout_mask(Tensor &opposite, float zoneout)
472 : */
473 : virtual void zoneout_mask(Tensor &opposite, float zoneout);
474 :
475 : /**
476 : * @copydoc Tensor::split(std::vector<size_t> sizes, int axis)
477 : */
478 : virtual std::vector<Tensor> split(std::vector<size_t> sizes, int axis);
479 :
480 : /**
481 : * @copydoc Tensor::concat()
482 : */
483 : virtual Tensor concat(const std::vector<Tensor> &tensors, int axis,
484 : Tensor &output);
485 :
486 : /**
487 : * @copydoc Tensor::print(std::ostream &out)
488 : */
489 : virtual void print(std::ostream &out) const = 0;
490 :
491 : /**
492 : * @copydoc Tensor::apply(std::function<T(T)> f, Tensor &output)
493 : * @note This will be only used in FloatTensor.
494 : */
495 : virtual Tensor &apply(std::function<float(float)> f, Tensor &output) const;
496 :
497 : #ifdef ENABLE_FP16
498 : /**
499 : * @copydoc Tensor::apply(std::function<T(T)> f, Tensor &output)
500 : * @note This will be only used in HalfTensor.
501 : */
502 : virtual Tensor &apply(std::function<_FP16(_FP16)> f, Tensor &output) const;
503 : #endif
504 :
505 : /**
506 : * @brief Copy the Tensor
507 : * @param[in] from Tensor to be copied
508 : *
509 : * @note copy can reshape the tensor to match the shape
510 : */
511 : virtual void copy(const Tensor &from) = 0;
512 :
513 : /**
514 : * @brief Copy the Tensor
515 : * @param[in] from Tensor to be copied
516 : */
517 : virtual void copyData(const Tensor &from) = 0;
518 :
519 : /**
520 : * @brief Copy the Tensor
521 : * @param[in] input Tensor to be copied
522 : * @param[out] output output Tensor
523 : */
524 : virtual void copy_with_stride(const Tensor &input, Tensor &output) = 0;
525 :
526 : /**
527 : * @brief Save the Tensor into file
528 : * @param[in] file input file stream
529 : */
530 : virtual void save(std::ostream &file);
531 :
532 : /**
533 : * @brief Read the Tensor from file
534 : * @param[in] file input file stream
535 : */
536 : virtual void read(std::ifstream &file, size_t start_offset = 0,
537 : bool read_from_offset = false);
538 :
539 : /**
540 : * @brief Read the Tensor from file
541 : * @param[in] file input file stream
542 : */
543 : virtual void read(ReadSource src, size_t start_offset = 0,
544 : bool read_from_offset = false);
545 :
546 : /**
547 : * @copydoc Tensor::readFSU()
548 : */
549 : virtual void readFSU();
550 :
551 : /**
552 : * @copydoc Tensor::argmax()
553 : */
554 : virtual std::vector<unsigned int> argmax() const;
555 :
556 : /**
557 : * @copydoc Tensor::argmin()
558 : */
559 : virtual std::vector<unsigned int> argmin() const;
560 :
561 : /**
562 : * @brief Compute top-K maximum values along the width dimension
563 : *
564 : * @details This function computes the top-K maximum values and their
565 : * corresponding indices along the **width** dimension for each batch,
566 : * channel, and height slice. The operation preserves the original tensor
567 : * format (NCHW/NHWC) while reducing the width dimension to size K. The
568 : * indices are stored in the provided `indices` array, and the top-K values
569 : * are stored in the provided `output_data` buffer.
570 : *
571 : * @param[in] k Number of largest elements to select (1 <= k <= width_size)
572 : * @param[out] output_data Buffer to store top-K values (must be
573 : * pre-allocated)
574 : * @param[out] indices Array to store corresponding indices (must be
575 : * pre-allocated)
576 : *
577 : * @throw std::invalid_argument If:
578 : * - k is 0 or exceeds width dimension size
579 : * - Called on non-floating point tensor (UINT8/UINT16/etc)
580 : */
581 : virtual void topK(unsigned int k, void *output_data, uint32_t *indices);
582 :
583 : /**
584 : * @copydoc Tensor::max_abs()
585 : */
586 : virtual float max_abs() const = 0;
587 :
588 : /**
589 : * @copydoc Tensor::maxValue()
590 : */
591 : virtual float maxValue() const = 0;
592 :
593 : /**
594 : * @copydoc Tensor::minValue()
595 : */
596 : virtual float minValue() const = 0;
597 :
598 : /**
599 : * @copydoc Tensor::transpose(const std::string &direction, Tensor &out)
600 : */
601 : virtual Tensor &transpose(const std::string &direction, Tensor &out) const;
602 :
603 : /**
604 : * @brief put data of Tensor
605 : * @note It is only effective when fsu is used
606 : */
607 : void putData() const;
608 :
609 : /**
610 : * @brief Set the memory buffer for the tensor
611 : * @param buf the memory buffer
612 : * @param off offset
613 : */
614 : void setMemoryData(const std::shared_ptr<MemoryData> buf, size_t off);
615 :
616 : /**
617 : * @brief return Data pointer of Tensor
618 : * @retval template T pointer (float pointer as default)
619 : */
620 : const std::shared_ptr<MemoryData> getMemoryData() const;
621 :
622 : /**
623 : * @brief return offset
624 : */
625 : size_t getOffset() const;
626 :
627 : /**
628 : * @brief get FileOffset of Tensor
629 : * @return size_t fileOffset
630 : */
631 : size_t getFileOffset() const;
632 :
633 : /**
634 : * @brief set FileOffset to Tensor
635 : * @param off FileOffset
636 : */
637 : void setFileOffset(size_t off);
638 :
639 : /**
640 : * @brief set Tensor Dim
641 : * @param[in] d TensorDim
642 : * @note Throws std::invalid_argument if size mismatch
643 : */
644 : void reshape(const TensorDim &d);
645 :
646 : /**
647 : * @brief return a copy of the Tensor Dim
648 : * @retval TensorDim
649 : */
650 25046 : TensorDim getDim() const { return TensorDim(dim); }
651 :
652 : /**
653 : * @brief return Tensor Type
654 : */
655 : TensorDim::TensorType getTensorType() const { return dim.getTensorType(); }
656 :
657 : /**
658 : * @brief Get initializer for the tensor
659 : * @retval initializer of the tensor
660 : */
661 1434 : Initializer getInitializer() const { return initializer; }
662 :
663 : /**
664 : * @brief Get format for the tensor
665 : * @retval format of the tensor
666 : */
667 : TensorDim::Format getFormat() const { return dim.getFormat(); }
668 :
669 : /**
670 : * @brief Get data type for the tensor
671 : * @retval data type of the tensor
672 : */
673 : Tdatatype getDataType() const { return dim.getDataType(); }
674 :
675 : /**
676 : * @brief update batch size for this tensor
677 : * @param batch size
678 : */
679 : void updateBatch(unsigned int batch);
680 :
681 : /**
682 : * @brief update the dimension for this tensor
683 : * @param dimension dimension to be updated
684 : */
685 : void updateDimension(TensorDim dimension);
686 :
687 : /**
688 : * @brief return whether tensor is contiguous or not.
689 : * @retval bool contiguous
690 : */
691 110616 : const bool getContiguous() const noexcept { return contiguous; }
692 :
693 : /**
694 : * @brief return current stride of tensor.
695 : * @retval int[MAXDIM] strides
696 : */
697 : const std::array<size_t, TensorDim::MAXDIM> getStrides() const noexcept {
698 81265 : return strides;
699 : }
700 :
701 : /**
702 : * @brief Set name of the tensor
703 : */
704 1199 : void setName(const std::string &name_) { name = name_; }
705 :
706 : /**
707 : * @brief Get name of the tensor
708 : * @retval string name
709 : */
710 85744 : const std::string &getName() const { return name; }
711 :
712 : /**
713 : * @brief Get linear index given the n-d index
714 : */
715 : size_t getIndex(unsigned int b, unsigned int c, unsigned int h,
716 : unsigned int w) const noexcept;
717 :
718 : /**
719 : * @brief Save quantization information
720 : */
721 0 : virtual void save_quantization_info(std::ostream &file) {}
722 :
723 : /**
724 : * @brief Read quantization information
725 : */
726 0 : virtual void read_quantization_info(std::ifstream &file,
727 : size_t start_offset = 0,
728 0 : bool read_from_offset = false) {}
729 :
730 : /**
731 : * @brief Read quantization information
732 : */
733 0 : virtual void read_quantization_info(ReadSource src, size_t start_offset = 0,
734 0 : bool read_from_offset = false) {}
735 :
736 : /**
737 : * @brief Get size of current tensor
738 : * @retval unsigned int size of the current tensor
739 : */
740 25131290 : virtual size_t size() const { return dim.getDataLen(); }
741 :
742 : /**
743 : * @brief Get if the tensor is empty
744 : * @retval true if the tensor is empty
745 : */
746 1649179 : bool empty() const { return size() == 0; }
747 :
748 : /**
749 : * @brief Get size of the data in bytes
750 : * @retval size_t Size in bytes
751 : */
752 25465 : size_t bytes() const { return size() * dim.getDataTypeSize(); }
753 :
754 : /**
755 : * @brief Get a total size of the memory data in bytes
756 : * @retval size_t Size in bytes
757 : */
758 38180 : virtual size_t getMemoryBytes() const {
759 38180 : return size() * dim.getDataTypeSize();
760 : }
761 :
762 : /**
763 : * @brief return Tensor batch size
764 : * @retval batch size
765 : */
766 5779517 : size_t batch() const { return dim.batch(); }
767 :
768 : /**
769 : * @brief return Tensor channel size
770 : * @retval channel size
771 : */
772 5734476 : size_t channel() const { return dim.channel(); }
773 :
774 : /**
775 : * @brief return Tensor height size
776 : * @retval height size
777 : */
778 5987775 : size_t height() const { return dim.height(); }
779 :
780 : /**
781 : * @brief return Tensor width size
782 : * @retval width size
783 : */
784 6113976 : size_t width() const { return dim.width(); }
785 :
786 : /**
787 : * @brief return Tensor scale factor size if exists
788 : * @retval scale factor size
789 : * @note Override for quantize tensor
790 : */
791 169008 : virtual size_t scale_size() const { return 0; }
792 :
793 : /**
794 : * @brief return Tensor quantization scheme
795 : * @retval Qscheme qscheme
796 : * @note Override for quantize tensor
797 : */
798 0 : virtual QScheme q_scheme() const {
799 : throw std::invalid_argument(
800 0 : "Tensor::q_scheme() is not supported in tensor data type " +
801 0 : getStringDataType());
802 : }
803 :
804 : /**
805 : * @brief Merge the given two axis for tensor at second axis inplace
806 : *
807 : * @param axis1 first axis to merge
808 : * @param axis2 second axis to merge
809 : */
810 : void mergeAxis(unsigned int axis1, unsigned int axis2);
811 :
812 : /**
813 : * @brief Allocate data based on the source tensor
814 : * @note As this memory is shared, do NOT initialize
815 : */
816 : void allocateSrcTensor();
817 :
818 : /**
819 : * @brief Update destination tensor to share memory with source tensor
820 : *
821 : * @param src src tensor containing the memory
822 : * @param dest destination tensor which will share the memory
823 : * @param offset offset to be used from the start of the data in bytes
824 : * @note The new tensor will share the same data as the current tensor but
825 : * can have different size.
826 : * @note New size added with offset must be less than the size of the original
827 : * tensor.
828 : */
829 : void createSharedDataTensor(const TensorBase *src, TensorBase *dest,
830 : size_t offset) const;
831 :
832 : /**
833 : * @brief Get new tensor which shares memory with current tensor but different
834 : * shape
835 : *
836 : * @param[in] dim new dimension to be set for this tensor
837 : * @param[in] offset offset to be used from the start of the data in elements
838 : * @param[in] reset_stride reset stride
839 : * @param[in] name_ name of the Tensor
840 : * @param[out] ret output TensorBase pointer
841 : * @note The new tensor will share the same data as the current tensor but
842 : * can have different size.
843 : * @note New size added with offset must be less than the size of the original
844 : * tensor.
845 : */
846 : void getSharedDataTensor(const TensorDim dim_, size_t offset,
847 : bool reset_stride, const std::string &name_,
848 : TensorBase *ret);
849 :
850 : /**
851 : * @copydoc Tensor::isValid()
852 : */
853 : virtual bool isValid() const = 0;
854 :
855 : static constexpr float epsilon = 1e-5f;
856 :
857 : protected:
858 : TensorDim dim;
859 : std::array<size_t, TensorDim::MAXDIM> strides;
860 : bool contiguous;
861 : Initializer initializer;
862 : std::string name; /**< name of the tensor */
863 : std::shared_ptr<MemoryData> data;
864 : size_t offset;
865 : size_t file_offset; /**< offset of the tensor in the file */
866 :
867 : /**<
868 : * When using shared_data with tensor, this stores the ptr of the source
869 : * tensor which handles the full memory. If tensor data is already allocated,
870 : * this does not affect the tensor. If the tensor data is not allocated, and
871 : * src_ptr is valid, this tensor will use the memory allocated by the src_ptr
872 : */
873 : std::shared_ptr<SrcSharedTensorBase> src_tensor;
874 :
875 : /**
876 : * @struct External Loop Info for broadcasted info
877 : * @brief External Loop Info for broadcasted iteration. Please refer to
878 : * DISABLED_private_external_loop_n in unittest_nntrainer_tensor.
879 : * @note This should better be implemented in iterator fashion before used
880 : * extensively.
881 : */
882 : struct BroadcastInfo {
883 :
884 : /**
885 : * @brief Construct a new External Loop Info object
886 : */
887 : BroadcastInfo() :
888 76768 : buffer_size(0),
889 76768 : buffer_axis(-1),
890 76768 : strides{0, 0, 0, 0},
891 : tensor_type({Tformat::NCHW, Tdatatype::FP32}) {}
892 :
893 : unsigned int buffer_size; /**< virtual size of the buffer */
894 : int buffer_axis; /**< the smallest axis that should be looped.
895 : -1 means no loop needed*/
896 : std::array<unsigned int, TensorDim::MAXDIM>
897 : strides; /**< modified strides for the loop */
898 : nntrainer::TensorDim::TensorType tensor_type;
899 : };
900 :
901 : /**
902 : * @brief compute Loop info for broadcasting and vectorization
903 : *
904 : * @param m target tensor to be calculated against.
905 : * @return BroadcastInfo Loopinfo needed to run external loop
906 : */
907 : BroadcastInfo computeBroadcastInfo(const Tensor &m) const;
908 :
909 : /**
910 : * @brief Calcuates variables needed to perform tensor flatten dot product
911 : *
912 : * @param[in] input Tensor
913 : * @param[in] output output Tensor
914 : * @param[in] trans Transpose
915 : * @param[in] trans_in Transpose input
916 : * @param[out] first_three_flat flattened the fist 3 axis
917 : * @param[out] last_axis last axis
918 : * @param[out] input_first_three_flat input's flattened the fist 3 axis
919 : * @param[out] input_last_axis input's last axis
920 : * @param[out] M number of op(this)'s and output's row
921 : * @param[out] N number of op(inputs)'s and output's columns
922 : * @param[out] K number of op(this)'s column and op(input)'s row
923 : * @param[out] lda leading dimension of this
924 : * @param[out] ldb leading dimension of input
925 : * @param[out] ldc leading dimension of output
926 : *
927 : * @note op(X) is one of X or X**T
928 : */
929 : void calculateFlattenDot(Tensor const &input, Tensor &output, bool trans,
930 : bool trans_in, unsigned int &first_three_flat,
931 : unsigned int &last_axis,
932 : unsigned int &input_first_three_flat,
933 : unsigned int &input_last_axis, unsigned int &M,
934 : unsigned int &N, unsigned int &K, unsigned int &lda,
935 : unsigned int &ldb, unsigned int &ldc) const;
936 :
937 : /**
938 : * @brief Get the Data Type String object
939 : * @return std::string of tensor data type
940 : * @note TensorBase::getStringDataType() should not be called. Please define
941 : * this function in the derived class to the corresponding data type.
942 : */
943 0 : virtual std::string getStringDataType() const { return "Undefined type"; }
944 : };
945 :
946 : /**
947 : * @class SrcSharedTensorBase
948 : * @brief Source of the shared tensor
949 : */
950 : class SrcSharedTensorBase {
951 : public:
952 : /**
953 : * @brief Constructor for the class
954 : */
955 : SrcSharedTensorBase() : src(nullptr), off(0) {}
956 :
957 : /**
958 : * @brief Constructor for the class
959 : */
960 301854 : SrcSharedTensorBase(const TensorBase *tensor, size_t offset) :
961 301854 : src(tensor), off(offset) {}
962 :
963 : /**
964 : * @brief Get the allocated src tensor
965 : */
966 603708 : const TensorBase *tensor() const {
967 603708 : if (!src)
968 0 : throw std::runtime_error("Accessing empty src tensor");
969 :
970 603708 : return src;
971 : }
972 :
973 : /**
974 : * @brief Get the offset from the source tensor
975 : */
976 301854 : size_t offset() const { return off; }
977 :
978 : private:
979 : const TensorBase *src; /**< Tensor of the source */
980 : size_t off; /**< offset from the source data ptr */
981 : };
982 :
983 : } // namespace nntrainer
984 :
985 : #endif /* __cplusplus */
986 : #endif /* __TENSOR_BASE_H__ */
|