Skip to content

Commit 1a667ba

Browse files
committed
[TensorV2] Add utility member functions to TensorV2 class
This pull request adds several new utility member functions to the TensorV2 class, enabling users to perform various tasks with their tensors more easily and efficiently. These include saving and loading tensors, updating batches, getting argmax and max absolute values, and more. The implementation is based on the current Tensor class and aims to improve the overall usability and flexibility of the TensorV2 class. **Changes proposed in this PR:** - Added save() and read() methods to allow saving and loading of saved tensor data. - Added Map() method to create a new Tensor object from a buffer. - Added argmax() and max_abs() methods to retrieve the indices of max value by batch and the value of the maximum absolute element in a tensor. - Added updateBatch() to update tensor batch size. **Self-evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: Donghyeon Jeong <dhyeon.jeong@samsung.com>
1 parent 789f07b commit 1a667ba

File tree

8 files changed

+281
-4
lines changed

8 files changed

+281
-4
lines changed

nntrainer/tensor/float_tensor.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,28 @@ void FloatTensor::copyData(const TensorV2 &from) {
635635
}
636636
}
637637

638+
std::vector<unsigned int> FloatTensor::argmax() const {
639+
std::vector<unsigned int> result;
640+
const float *data = (float *)getData();
641+
size_t batch_size = batch();
642+
size_t feature_len = dim.getFeatureLen();
643+
644+
result.resize(batch_size);
645+
646+
for (unsigned int b = 0; b < batch_size; b++) {
647+
auto max_iter =
648+
std::max_element(data + b * feature_len, data + (b + 1) * feature_len);
649+
result[b] = std::distance(data, max_iter) - (b * feature_len);
650+
}
651+
return result;
652+
}
653+
654+
float FloatTensor::max_abs() const {
655+
const float *data = (float *)getData();
656+
unsigned int idx = isamax(size(), data, 1);
657+
return *(data + idx);
658+
}
659+
638660
TensorV2 &FloatTensor::transpose(const std::string &direction,
639661
TensorV2 &output) const {
640662
unsigned int SL, SI, SJ, SK;

nntrainer/tensor/float_tensor.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,16 @@ class FloatTensor : public TensorBase {
285285
*/
286286
void copyData(const TensorV2 &from);
287287

288+
/**
289+
* @copydoc TensorV2::argmax()
290+
*/
291+
std::vector<unsigned int> argmax() const override;
292+
293+
/**
294+
* @copydoc TensorV2::max_abs()
295+
*/
296+
float max_abs() const override;
297+
288298
/**
289299
* @copydoc TensorV2::transpose(const std::string &direction, TensorV2 &out)
290300
*/

nntrainer/tensor/half_tensor.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,29 @@ void HalfTensor::copyData(const TensorV2 &from) {
685685
}
686686
}
687687

688+
std::vector<unsigned int> HalfTensor::argmax() const {
689+
std::vector<unsigned int> result;
690+
const _FP16 *data = (_FP16 *)getData();
691+
size_t batch_size = batch();
692+
size_t feature_len = dim.getFeatureLen();
693+
694+
result.resize(batch_size);
695+
696+
for (unsigned int b = 0; b < batch_size; b++) {
697+
auto max_iter =
698+
std::max_element(data + b * feature_len, data + (b + 1) * feature_len);
699+
result[b] = std::distance(data, max_iter) - (b * feature_len);
700+
}
701+
702+
return result;
703+
}
704+
705+
float HalfTensor::max_abs() const {
706+
const _FP16 *data = (_FP16 *)getData();
707+
unsigned int idx = isamax(size(), data, 1);
708+
return (float)(*(data + idx));
709+
}
710+
688711
TensorV2 &HalfTensor::transpose(const std::string &direction,
689712
TensorV2 &output) const {
690713
unsigned int SL, SI, SJ, SK;

nntrainer/tensor/half_tensor.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,16 @@ class HalfTensor : public TensorBase {
284284
*/
285285
void copyData(const TensorV2 &from);
286286

287+
/**
288+
* @copydoc TensorV2::argmax()
289+
*/
290+
std::vector<unsigned int> argmax() const override;
291+
292+
/**
293+
* @copydoc TensorV2::max_abs()
294+
*/
295+
float max_abs() const override;
296+
287297
/**
288298
* @copydoc TensorV2::transpose(const std::string &direction, TensorV2 &out)
289299
*/

nntrainer/tensor/tensor_base.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,28 @@ bool TensorBase::operator==(const TensorBase &rhs) const {
4040
return true;
4141
}
4242

43+
void TensorBase::setTensorVar(TensorDim d, void *buf, size_t offset) {
44+
dim = d;
45+
strides = d.computeStrides();
46+
/// Tensor does not own the memory
47+
data = std::shared_ptr<MemoryData>(new MemoryData((void *)buf),
48+
std::default_delete<MemoryData>());
49+
offset = offset;
50+
}
51+
4352
void TensorBase::putData() const {
4453
if (!data)
4554
return;
4655

4756
data->invalidate();
4857
}
4958

59+
const std::shared_ptr<MemoryData> TensorBase::getMemoryData() const {
60+
return data;
61+
}
62+
63+
size_t TensorBase::getOffset() const { return offset; }
64+
5065
void TensorBase::reshape(const TensorDim &d) {
5166
NNTR_THROW_IF(!contiguous, std::invalid_argument)
5267
<< getName() << " is not contiguous, cannot reshape.";
@@ -64,6 +79,16 @@ void TensorBase::reshape(const TensorDim &d) {
6479
strides = d.computeStrides();
6580
}
6681

82+
void TensorBase::updateBatch(unsigned int batch) {
83+
if (dim.batch() == batch) {
84+
return;
85+
}
86+
87+
if (isAllocated())
88+
throw std::invalid_argument("Cannot update batch for an allocated tensor");
89+
dim.batch(batch);
90+
}
91+
6792
size_t TensorBase::getIndex(unsigned int b, unsigned int c, unsigned int h,
6893
unsigned int w) const noexcept {
6994
if (getFormat() == Tformat::NCHW) {

nntrainer/tensor/tensor_base.h

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,11 @@ class TensorBase {
127127
*/
128128
bool operator!=(const TensorBase &rhs) const { return !(*this == rhs); }
129129

130+
/**
131+
* @copydoc TensorV2::setTensorVar(TensorDim d, void *buf, size_t offset)
132+
*/
133+
void setTensorVar(TensorDim d, void *buf, size_t offset);
134+
130135
/**
131136
* @brief Basic Destructor
132137
*/
@@ -335,6 +340,16 @@ class TensorBase {
335340
*/
336341
virtual void copyData(const TensorV2 &from) = 0;
337342

343+
/**
344+
* @copydoc TensorV2::argmax()
345+
*/
346+
virtual std::vector<unsigned int> argmax() const = 0;
347+
348+
/**
349+
* @copydoc TensorV2::max_abs()
350+
*/
351+
virtual float max_abs() const = 0;
352+
338353
/**
339354
* @copydoc TensorV2::transpose(const std::string &direction, TensorV2 &out)
340355
*/
@@ -347,6 +362,17 @@ class TensorBase {
347362
*/
348363
void putData() const;
349364

365+
/**
366+
* @brief return Data pointer of Tensor
367+
* @retval template T pointer (float pointer as default)
368+
*/
369+
const std::shared_ptr<MemoryData> getMemoryData() const;
370+
371+
/**
372+
* @brief return offset
373+
*/
374+
size_t getOffset() const;
375+
350376
/**
351377
* @brief set Tensor Dim
352378
* @param[in] d TensorDim
@@ -383,6 +409,12 @@ class TensorBase {
383409
*/
384410
Tdatatype getDataType() const { return dim.getDataType(); }
385411

412+
/**
413+
* @brief update batch size for this tensor
414+
* @param batch size
415+
*/
416+
void updateBatch(unsigned int batch);
417+
386418
/**
387419
* @brief return whether tensor is contiguous or not.
388420
* @retval bool contiguous
@@ -591,8 +623,7 @@ class SrcSharedTensorBase {
591623
* @brief Constructor for the class
592624
*/
593625
SrcSharedTensorBase(const TensorBase *tensor, size_t offset) :
594-
src(tensor),
595-
off(offset) {}
626+
src(tensor), off(offset) {}
596627

597628
/**
598629
* @brief Get the allocated src tensor

nntrainer/tensor/tensor_v2.cpp

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,12 @@ void TensorV2::print(std::ostream &out) const { itensor->print(out); }
504504

505505
void TensorV2::putData() const { itensor->putData(); }
506506

507+
const std::shared_ptr<MemoryData> TensorV2::getMemoryData() const {
508+
return itensor->getMemoryData();
509+
}
510+
511+
size_t TensorV2::getOffset() const { return itensor->getOffset(); }
512+
507513
void TensorV2::copy(const TensorV2 &from) {
508514
/// @todo enable copy to non-contiguous tensor
509515
if (!itensor->getContiguous()) {
@@ -575,6 +581,45 @@ TensorV2 TensorV2::clone() const {
575581
return output;
576582
}
577583

584+
void TensorV2::save(std::ostream &file) {
585+
NNTR_THROW_IF(!getContiguous(), std::invalid_argument)
586+
<< getName() << " is not contiguous, cannot save.";
587+
588+
std::streamsize sz = static_cast<std::streamsize>(bytes());
589+
NNTR_THROW_IF(sz < 0, std::invalid_argument)
590+
<< "save size: " << bytes()
591+
<< " is too big. It cannot be represented by std::streamsize";
592+
593+
checkedWrite(file, getData<char>(), sz, "[Tensor::save] operation failed");
594+
putData();
595+
}
596+
597+
void TensorV2::read(std::ifstream &file) {
598+
NNTR_THROW_IF(!getContiguous(), std::invalid_argument)
599+
<< getName() << " is not contiguous, cannot read.";
600+
601+
std::streamsize sz = static_cast<std::streamsize>(bytes());
602+
603+
NNTR_THROW_IF(sz < 0, std::invalid_argument)
604+
<< "read size: " << bytes()
605+
<< " is too big. It cannot be represented by std::streamsize";
606+
607+
checkedRead(file, getData<char>(), sz, "[Tensor::read] operation failed");
608+
putData();
609+
}
610+
611+
std::vector<unsigned int> TensorV2::argmax() const {
612+
NNTR_THROW_IF(!getContiguous(), std::invalid_argument)
613+
<< getName() << " is not contiguous, cannot get argmax.";
614+
return itensor->argmax();
615+
}
616+
617+
float TensorV2::max_abs() const {
618+
NNTR_THROW_IF(!getContiguous(), std::invalid_argument)
619+
<< getName() << " is not contiguous, cannot get max_abs.";
620+
return itensor->max_abs();
621+
}
622+
578623
TensorV2 TensorV2::transpose(const std::string &direction) const {
579624
TensorV2 output(getDim());
580625
transpose(direction, output);
@@ -612,12 +657,14 @@ TensorDim::Format TensorV2::getFormat() const { return itensor->getFormat(); }
612657

613658
Tdatatype TensorV2::getDataType() const { return itensor->getDataType(); }
614659

660+
void TensorV2::updateBatch(unsigned int batch) { itensor->updateBatch(batch); }
661+
615662
const bool TensorV2::getContiguous() const noexcept {
616663
return itensor->getContiguous();
617664
}
618665

619-
const std::array<size_t, TensorDim::MAXDIM> TensorV2::getStrides() const
620-
noexcept {
666+
const std::array<size_t, TensorDim::MAXDIM>
667+
TensorV2::getStrides() const noexcept {
621668
return itensor->getStrides();
622669
}
623670

@@ -677,4 +724,13 @@ TensorV2 TensorV2::getSharedDataTensor(const TensorDim dim_, size_t offset,
677724
return ret;
678725
}
679726

727+
void TensorV2::setTensorVar(TensorDim d, void *buf, size_t offset) {
728+
itensor->setTensorVar(d, buf, offset);
729+
}
730+
731+
std::ostream &operator<<(std::ostream &out, TensorV2 const &input) {
732+
input.print(out);
733+
return out;
734+
}
735+
680736
} // namespace nntrainer

0 commit comments

Comments
 (0)