From 3bb1bc1189bfa14670d2f7839d708f443f5b5942 Mon Sep 17 00:00:00 2001 From: Kevin Cheng Date: Thu, 17 Jun 2021 15:57:08 -0700 Subject: Constant data is embedded in flatbuffer as u8 array instead of saving out as separate numpy files now. Change-Id: I9d757ee3bdc637595732b06c5319d1dc957eaf96 --- include/tosa_generated.h | 25 ++-- include/tosa_serialization_handler.h | 29 +++- python/tosa/TosaTensor.py | 29 +++- schema/tosa.fbs | 8 +- src/tosa_serialization_handler.cpp | 268 ++++++++++++++++++++++++++++++++--- 5 files changed, 313 insertions(+), 46 deletions(-) diff --git a/include/tosa_generated.h b/include/tosa_generated.h index 735aca8..0f73819 100644 --- a/include/tosa_generated.h +++ b/include/tosa_generated.h @@ -1951,7 +1951,7 @@ struct TosaTensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_NAME = 4, VT_SHAPE = 6, VT_TYPE = 8, - VT_NPY_FILENAME = 10 + VT_DATA = 10 }; const flatbuffers::String *name() const { return GetPointer(VT_NAME); @@ -1962,8 +1962,8 @@ struct TosaTensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { tosa::DType type() const { return static_cast(GetField(VT_TYPE, 0)); } - const flatbuffers::String *npy_filename() const { - return GetPointer(VT_NPY_FILENAME); + const flatbuffers::Vector *data() const { + return GetPointer *>(VT_DATA); } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && @@ -1972,8 +1972,8 @@ struct TosaTensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyOffset(verifier, VT_SHAPE) && verifier.VerifyVector(shape()) && VerifyField(verifier, VT_TYPE) && - VerifyOffset(verifier, VT_NPY_FILENAME) && - verifier.VerifyString(npy_filename()) && + VerifyOffset(verifier, VT_DATA) && + verifier.VerifyVector(data()) && verifier.EndTable(); } }; @@ -1991,8 +1991,8 @@ struct TosaTensorBuilder { void add_type(tosa::DType type) { fbb_.AddElement(TosaTensor::VT_TYPE, static_cast(type), 0); } - void add_npy_filename(flatbuffers::Offset npy_filename) { - fbb_.AddOffset(TosaTensor::VT_NPY_FILENAME, npy_filename); + void add_data(flatbuffers::Offset> data) { + fbb_.AddOffset(TosaTensor::VT_DATA, data); } explicit TosaTensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { @@ -2011,9 +2011,9 @@ inline flatbuffers::Offset CreateTosaTensor( flatbuffers::Offset name = 0, flatbuffers::Offset> shape = 0, tosa::DType type = tosa::DType_UNKNOWN, - flatbuffers::Offset npy_filename = 0) { + flatbuffers::Offset> data = 0) { TosaTensorBuilder builder_(_fbb); - builder_.add_npy_filename(npy_filename); + builder_.add_data(data); builder_.add_type(type); builder_.add_shape(shape); builder_.add_name(name); @@ -2025,16 +2025,17 @@ inline flatbuffers::Offset CreateTosaTensorDirect( const char *name = nullptr, const std::vector *shape = nullptr, tosa::DType type = tosa::DType_UNKNOWN, - const char *npy_filename = nullptr) { + const std::vector *data = nullptr) { auto name__ = name ? _fbb.CreateString(name) : 0; auto shape__ = shape ? _fbb.CreateVector(*shape) : 0; - auto npy_filename__ = npy_filename ? _fbb.CreateString(npy_filename) : 0; + if (data) { _fbb.ForceVectorAlignment(data->size(), sizeof(uint8_t), 8); } + auto data__ = data ? _fbb.CreateVector(*data) : 0; return tosa::CreateTosaTensor( _fbb, name__, shape__, type, - npy_filename__); + data__); } struct TosaOperator FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { diff --git a/include/tosa_serialization_handler.h b/include/tosa_serialization_handler.h index 398590d..db9481b 100644 --- a/include/tosa_serialization_handler.h +++ b/include/tosa_serialization_handler.h @@ -26,6 +26,8 @@ #include #include +#define TENSOR_BUFFER_FORCE_ALIGNMENT 8 + namespace tosa { @@ -108,13 +110,13 @@ class TosaSerializationTensor public: // constructor and destructor TosaSerializationTensor(const flatbuffers::String* name, - const flatbuffers::Vector& shape, + const flatbuffers::Vector* shape, DType dtype, - const flatbuffers::String* npy_filename); + const flatbuffers::Vector* data); TosaSerializationTensor(std::string& name, const std::vector& shape, DType dtype, - const std::string& npy_filename); + const std::vector& data); TosaSerializationTensor(); ~TosaSerializationTensor(); @@ -131,9 +133,9 @@ public: { return _dtype; } - const std::string& GetNpyFilePtr() const + const std::vector& GetData() const { - return _npy_filename; + return _data; } // modifier @@ -150,7 +152,7 @@ private: DType _dtype; /* data type enumeration, see tosa_isa_generated.h */ std::vector _shape; /* shape of the tensor */ std::string _name; /* name of the tensor, used for solving dependency */ - std::string _npy_filename; /* numpy array filename if not null. so null is the distinguisher */ + std::vector _data; /* data array */ }; class TosaSerializationOperator @@ -283,6 +285,21 @@ public: tosa_err_t SaveFileTosaFlatbuffer(const char* filename); tosa_err_t LoadFileSchema(const char* schema_filename); + // data format conversion. little-endian. + static tosa_err_t ConvertF32toU8(const std::vector& in, std::vector& out); + static tosa_err_t ConvertI48toU8(const std::vector& in, std::vector& out); + static tosa_err_t ConvertI32toU8(const std::vector& in, std::vector& out); + static tosa_err_t ConvertI16toU8(const std::vector& in, std::vector& out); + static tosa_err_t ConvertI8toU8(const std::vector& in, std::vector& out); + static tosa_err_t ConvertBooltoU8(const std::vector& in, std::vector& out); + + static tosa_err_t ConvertU8toF32(const std::vector& in, uint32_t out_size, std::vector& out); + static tosa_err_t ConvertU8toI48(const std::vector& in, uint32_t out_size, std::vector& out); + static tosa_err_t ConvertU8toI32(const std::vector& in, uint32_t out_size, std::vector& out); + static tosa_err_t ConvertU8toI16(const std::vector& in, uint32_t out_size, std::vector& out); + static tosa_err_t ConvertU8toI8(const std::vector& in, uint32_t out_size, std::vector& out); + static tosa_err_t ConvertU8toBool(const std::vector& in, uint32_t out_size, std::vector& out); + // version const TosaVersion& GetTosaVersion() const { diff --git a/python/tosa/TosaTensor.py b/python/tosa/TosaTensor.py index 760c091..9c0b3cf 100644 --- a/python/tosa/TosaTensor.py +++ b/python/tosa/TosaTensor.py @@ -81,16 +81,37 @@ class TosaTensor(object): return 0 # TosaTensor - def NpyFilename(self): + def Data(self, j): o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) if o != 0: - return self._tab.String(o + self._tab.Pos) - return None + a = self._tab.Vector(o) + return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1)) + return 0 + + # TosaTensor + def DataAsNumpy(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + if o != 0: + return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o) + return 0 + + # TosaTensor + def DataLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + if o != 0: + return self._tab.VectorLen(o) + return 0 + + # TosaTensor + def DataIsNone(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10)) + return o == 0 def TosaTensorStart(builder): builder.StartObject(4) def TosaTensorAddName(builder, name): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(name), 0) def TosaTensorAddShape(builder, shape): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(shape), 0) def TosaTensorStartShapeVector(builder, numElems): return builder.StartVector(4, numElems, 4) def TosaTensorAddType(builder, type): builder.PrependUint32Slot(2, type, 0) -def TosaTensorAddNpyFilename(builder, npyFilename): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(npyFilename), 0) +def TosaTensorAddData(builder, data): builder.PrependUOffsetTRelativeSlot(3, flatbuffers.number_types.UOffsetTFlags.py_type(data), 0) +def TosaTensorStartDataVector(builder, numElems): return builder.StartVector(1, numElems, 1) def TosaTensorEnd(builder): return builder.EndObject() diff --git a/schema/tosa.fbs b/schema/tosa.fbs index d64a50c..9c8add8 100644 --- a/schema/tosa.fbs +++ b/schema/tosa.fbs @@ -276,10 +276,10 @@ table Version { } table TosaTensor { - name:string; // name of the tensor, used for solving dependency - shape:[int32]; // shape of the tensor - type:DType; // data type of the tensor - npy_filename: string; // numpy array filename + name:string; // name of the tensor, used for solving dependency + shape:[int32]; // shape of the tensor + type:DType; // data type of the tensor + data: [ubyte] (force_align: 8); // raw data array if it's a constant tensor. } table TosaOperator { diff --git a/src/tosa_serialization_handler.cpp b/src/tosa_serialization_handler.cpp index 4fe152f..d153dc5 100644 --- a/src/tosa_serialization_handler.cpp +++ b/src/tosa_serialization_handler.cpp @@ -19,32 +19,32 @@ using namespace tosa; TosaSerializationTensor::TosaSerializationTensor(const flatbuffers::String* name, - const flatbuffers::Vector& shape, + const flatbuffers::Vector* shape, DType dtype, - const flatbuffers::String* npy_filename) + const flatbuffers::Vector* data) { _dtype = dtype; - std::copy(shape.begin(), shape.end(), std::back_inserter(_shape)); + std::copy(shape->begin(), shape->end(), std::back_inserter(_shape)); assert(name); _name = name->str(); - if (npy_filename) + if (data) { - _npy_filename = npy_filename->str(); + std::copy(data->begin(), data->end(), std::back_inserter(_data)); } } TosaSerializationTensor::TosaSerializationTensor(std::string& name, const std::vector& shape, DType dtype, - const std::string& npy_filename) + const std::vector& data) { - _dtype = dtype; - _shape = shape; - _name = name; - _npy_filename = npy_filename; + _dtype = dtype; + _shape = shape; + _name = name; + _data = data; } TosaSerializationTensor::TosaSerializationTensor() @@ -483,12 +483,12 @@ tosa_err_t TosaSerializationHandler::InitWithBuf(const uint8_t* buf) { auto curr_tensor = fb_tosa_tensors->Get(j); - auto tensor_name = curr_tensor->name(); - auto tensor_shape = curr_tensor->shape(); - auto tensor_type = curr_tensor->type(); - auto tensor_npy_filename = curr_tensor->npy_filename(); + auto tensor_name = curr_tensor->name(); + auto tensor_shape = curr_tensor->shape(); + auto tensor_type = curr_tensor->type(); + auto tensor_data = curr_tensor->data(); - new_tensor = new TosaSerializationTensor(tensor_name, *tensor_shape, tensor_type, tensor_npy_filename); + new_tensor = new TosaSerializationTensor(tensor_name, tensor_shape, tensor_type, tensor_data); if (new_tensor) { block_tensors_container.push_back(new_tensor); @@ -734,12 +734,9 @@ tosa_err_t TosaSerializationHandler::FreezeBuilder() auto tensor_name = _builder.CreateString(tensor->GetName().c_str()); auto tensor_shape = _builder.CreateVector(tensor->GetShape()); auto tensor_dtype = tensor->GetDtype(); - flatbuffers::Offset tensor_npy_filename = 0; - if (!tensor->GetNpyFilePtr().empty()) - tensor_npy_filename = _builder.CreateString(tensor->GetNpyFilePtr().c_str()); + auto tensor_data = _builder.CreateVector(tensor->GetData()); - auto fboffset_tensor = - CreateTosaTensor(_builder, tensor_name, tensor_shape, tensor_dtype, tensor_npy_filename); + auto fboffset_tensor = CreateTosaTensor(_builder, tensor_name, tensor_shape, tensor_dtype, tensor_data); fboffset_block_tensors.push_back(fboffset_tensor); } @@ -760,3 +757,234 @@ tosa_err_t TosaSerializationHandler::FreezeBuilder() return TOSA_OK; } + +void zero_pad(std::vector& buf) +{ + while ((buf.size() % TENSOR_BUFFER_FORCE_ALIGNMENT) != 0) + { + buf.push_back(0); + } +} + +tosa_err_t TosaSerializationHandler::ConvertF32toU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint32_t* val_u32 = reinterpret_cast(&val); + out.push_back(*val_u32 & 0xFF); + out.push_back((*val_u32 >> 8) & 0xFF); + out.push_back((*val_u32 >> 16) & 0xFF); + out.push_back((*val_u32 >> 24) & 0xFF); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertI48toU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint64_t* val_u64 = reinterpret_cast(&val); + out.push_back(*val_u64 & 0xFF); + out.push_back((*val_u64 >> 8) & 0xFF); + out.push_back((*val_u64 >> 16) & 0xFF); + out.push_back((*val_u64 >> 24) & 0xFF); + out.push_back((*val_u64 >> 32) & 0xFF); + out.push_back((*val_u64 >> 40) & 0xFF); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertI32toU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint32_t* val_u32 = reinterpret_cast(&val); + out.push_back(*val_u32 & 0xFF); + out.push_back((*val_u32 >> 8) & 0xFF); + out.push_back((*val_u32 >> 16) & 0xFF); + out.push_back((*val_u32 >> 24) & 0xFF); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertI16toU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint16_t* val_u16 = reinterpret_cast(&val); + out.push_back(*val_u16 & 0xFF); + out.push_back((*val_u16 >> 8) & 0xFF); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertI8toU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint8_t* val_u8 = reinterpret_cast(&val); + out.push_back(*val_u8); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertBooltoU8(const std::vector& in, std::vector& out) +{ + out.clear(); + for (auto val : in) + { + uint8_t* val_u8 = reinterpret_cast(&val); + out.push_back(*val_u8); + } + zero_pad(out); + return TOSA_OK; +} + +tosa_err_t + TosaSerializationHandler::ConvertU8toF32(const std::vector& in, uint32_t out_size, std::vector& out) +{ + out.clear(); + if (in.size() < out_size * sizeof(float)) + { + printf("TosaSerializationHandler::ConvertU8toF32(): uint8 buffer size %ld must >= target size %ld\n", in.size(), + out_size * sizeof(float)); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint32_t byte0 = in[i * sizeof(float)]; + uint32_t byte1 = in[i * sizeof(float) + 1]; + uint32_t byte2 = in[i * sizeof(float) + 2]; + uint32_t byte3 = in[i * sizeof(float) + 3]; + uint32_t val_u32 = byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24); + float* val_fp32 = reinterpret_cast(&val_u32); + out.push_back(*val_fp32); + } + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertU8toI48(const std::vector& in, + uint32_t out_size, + std::vector& out) +{ + out.clear(); + if (in.size() < out_size * 6 /* sizeof(int48) */) + { + printf("TosaSerializationHandler::ConvertU8toI48(): uint8 buffer size %ld must >= target size %d\n", in.size(), + out_size * 6); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint64_t byte0 = in[i * 6]; + uint64_t byte1 = in[i * 6 + 1]; + uint64_t byte2 = in[i * 6 + 2]; + uint64_t byte3 = in[i * 6 + 3]; + uint64_t byte4 = in[i * 6 + 4]; + uint64_t byte5 = in[i * 6 + 5]; + bool sign = ((byte5 >> 7) & 1) == 1 ? true : false; + uint64_t val_u64 = byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24) + (byte4 << 32) + (byte5 << 40); + if (sign) + { + uint64_t sext_mask = (0xFFFFUL << 48); + val_u64 |= sext_mask; + } + int64_t* val_i64 = reinterpret_cast(&val_u64); + out.push_back(*val_i64); + } + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertU8toI32(const std::vector& in, + uint32_t out_size, + std::vector& out) +{ + out.clear(); + if (in.size() < out_size * sizeof(int32_t)) + { + printf("TosaSerializationHandler::ConvertU8toI32(): uint8 buffer size %ld must >= target size %ld\n", in.size(), + out_size * sizeof(int32_t)); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint32_t byte0 = in[i * sizeof(int32_t)]; + uint32_t byte1 = in[i * sizeof(int32_t) + 1]; + uint32_t byte2 = in[i * sizeof(int32_t) + 2]; + uint32_t byte3 = in[i * sizeof(int32_t) + 3]; + uint32_t val_u32 = byte0 + (byte1 << 8) + (byte2 << 16) + (byte3 << 24); + int32_t* val_i32 = reinterpret_cast(&val_u32); + out.push_back(*val_i32); + } + return TOSA_OK; +} + +tosa_err_t TosaSerializationHandler::ConvertU8toI16(const std::vector& in, + uint32_t out_size, + std::vector& out) +{ + out.clear(); + if (in.size() < out_size * sizeof(int16_t)) + { + printf("TosaSerializationHandler::ConvertU8toI16(): uint8 buffer size %ld must >= target size %ld\n", in.size(), + out_size * sizeof(int16_t)); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint16_t byte0 = in[i * sizeof(int16_t)]; + uint16_t byte1 = in[i * sizeof(int16_t) + 1]; + uint16_t val_u16 = byte0 + (byte1 << 8); + int16_t* val_i16 = reinterpret_cast(&val_u16); + out.push_back(*val_i16); + } + return TOSA_OK; +} + +tosa_err_t + TosaSerializationHandler::ConvertU8toI8(const std::vector& in, uint32_t out_size, std::vector& out) +{ + out.clear(); + if (in.size() < out_size * sizeof(int8_t)) + { + printf("TosaSerializationHandler::ConvertU8toI8(): uint8 buffer size %ld must >= target size %ld\n", in.size(), + out_size * sizeof(bool)); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint8_t val_u8 = in[i]; + int8_t* val_i8 = reinterpret_cast(&val_u8); + out.push_back(*val_i8); + } + return TOSA_OK; +} + +tosa_err_t + TosaSerializationHandler::ConvertU8toBool(const std::vector& in, uint32_t out_size, std::vector& out) +{ + out.clear(); + if (in.size() < out_size * sizeof(bool)) + { + printf("TosaSerializationHandler::ConvertU8toBool(): uint8 buffer size %ld must >= target size %ld\n", + in.size(), out_size * sizeof(bool)); + return TOSA_USER_ERROR; + } + for (int i = 0; i < out_size; i++) + { + uint8_t val_u8 = in[i]; + bool* val_bool = reinterpret_cast(&val_u8); + out.push_back(*val_bool); + } + return TOSA_OK; +} -- cgit v1.2.1