From e5e2676409a936431f87d31fb74d825257b20804 Mon Sep 17 00:00:00 2001 From: Eric Kunze Date: Tue, 13 Oct 2020 16:11:07 -0700 Subject: Initial checkin of TOSA reference_model and tests Change-Id: I2f8e7fa63e2ae40203e57d2cc8814bde3b312cb6 Signed-off-by: Eric Kunze --- reference_model/src/tensor.h | 815 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 815 insertions(+) create mode 100644 reference_model/src/tensor.h (limited to 'reference_model/src/tensor.h') diff --git a/reference_model/src/tensor.h b/reference_model/src/tensor.h new file mode 100644 index 0000000..2fd37cd --- /dev/null +++ b/reference_model/src/tensor.h @@ -0,0 +1,815 @@ + +// Copyright (c) 2020, ARM Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef TOSA_REFERENCE_TENSOR_H +#define TOSA_REFERENCE_TENSOR_H + +#include "model_common.h" +#include "ops/template_types.h" +#include "tosa_generated.h" +#include "tosa_serialization_handler.h" +#include +#include +#include + +using namespace tosa; + +namespace TosaReference +{ +class GraphNode; + +class Tensor +{ +public: + Tensor(std::string tensorName_, + DType tensorDtype__, + const std::vector& tensorUsage_, + const std::vector& tensorFormat_, + std::vector shape_, + int isConst_); + + virtual ~Tensor(); + + int setIsSubgraphInput(); + int setIsSubgraphOutput(); + + int getIsSubgraphInput() const + { + return isSubgraphInput; + } + + int getIsSubgraphOutput() const + { + return isSubgraphOutput; + } + + int setProducer(GraphNode* node); + int addConsumer(GraphNode* node); + + int setIsValid() + { + isValid = 1; + return 0; + } + + int clearIsValid() + { + isValid = 0; + return 0; + } + + int getIsValid() const + { + return isValid; + } + + int getIsConst() const + { + return isConst; + } + + GraphNode* getProducer() + { + return producer; + } + + std::vector& getConsumers() + { + return consumers; + } + + const std::string& getName() const + { + return tensorName; + } + + const std::vector& getShape() const + { + return shape; + } + + std::string getShapeAsString() const + { + std::string shape_str("["); + for (auto& dim : shape) + { + shape_str += (std::to_string(dim) + ", "); + } + shape_str.append("]"); + return shape_str; + } + + const std::vector& getUsage() const + { + return tensorUsage; + } + + bool hasUsage(Usage usage) const + { + for (auto& usg : tensorUsage) + { + if (usg == usage) + { + return true; + } + } + return false; + } + + std::string getUsageAsString() const + { + std::string usage_str("["); + for (auto& usg : tensorUsage) + { + usage_str += (std::string(EnumNamesUsage()[usg]) + ", "); + } + usage_str.append("]"); + return usage_str; + } + + const std::vector& getFormat() const + { + return tensorFormat; + } + + bool hasFormat(Format format) const + { + for (auto& fmt : tensorFormat) + { + if (fmt == format) + { + return true; + } + } + return false; + } + + std::string getFormatAsString() const + { + std::string format_str("["); + for (auto& fmt : tensorFormat) + { + format_str += (std::string(EnumNamesFormat()[fmt]) + ", "); + } + format_str.append("]"); + return format_str; + } + + const uint32_t getElementCount() const + { + uint32_t elements = 1; + for (size_t i = 0; i < shape.size(); i++) + elements *= shape[i]; + + return elements; + } + + // Comparison of rank and type with other tensors + const int matchRank(const Tensor& ref) const + { + return (ref.shape.size() == shape.size()) ? 0 : 1; + } + + const int matchType(const Tensor& ref) const + { + return (ref.tensorDtype == tensorDtype) ? 0 : 1; + } + + const int matchRankType(const Tensor& ref) const + { + return (matchType(ref) || matchRank(ref)); + } + + const int matchRankTypeShape(const Tensor& ref, const bool broadcastOk = false) const + { + if (matchRankType(ref)) + return 1; + + for (size_t i = 0; i < shape.size(); i++) + { + if (shape[i] != ref.shape[i]) + { + if (!broadcastOk || + // For broadcasts, at least one operand must have size 1 + // if they don't both match + (broadcastOk && (shape[i] != 1 && ref.shape[i] != 1))) + { + return 1; + } + } + } + + return 0; + } + + // Sometimes we might want to match several semi-compatible types, + // so just check rank and size here + const int matchRankSize(const Tensor& ref) const + { + if (matchRank(ref)) + return 1; + + for (size_t i = 0; i < shape.size(); i++) + { + if (shape[i] != ref.shape[i]) + return 1; + } + + return 0; + } + + // Unary check to make sure rank matches + const int checkRequiredRank(const int exactRank) const + { + return (shape.size() == (size_t)exactRank) ? 0 : 1; + } + + const int checkRequiredRank(const int minRank, const int maxRank) const + { + return (shape.size() >= (size_t)minRank && shape.size() <= (size_t)maxRank) ? 0 : 1; + } + + const int getRank() const + { + return shape.size(); + } + + const DType getDtype() const + { + return tensorDtype; + } + + virtual int dumpTensor(FILE* out) const = 0; + virtual int dumpTensorParams(FILE* out) const; + virtual int dumpTensorParams(std::ostream& out) const; + + virtual int setTensorValueFloat(const size_t bufLen, const float* vals) = 0; + virtual int setTensorValueInt32(const size_t bufLen, const int32_t* vals) = 0; + virtual int setTensorValueInt64(const size_t bufLen, const int64_t* vals) = 0; + virtual int setTensorValueBool(const size_t bufLen, const bool* vals) = 0; + virtual int getTensorValueFloat(const size_t bufLen, float* fbuf) const = 0; + virtual int getTensorValueInt32(const size_t bufLen, int32_t* ibuf) const = 0; + virtual int getTensorValueInt64(const size_t bufLen, int64_t* ibuf) const = 0; + virtual int getTensorValueBool(const size_t bufLen, bool* ibuf) const = 0; + + virtual int readFromNpyFile(const char* filename); + virtual int writeToNpyFile(const char* filename) const; + virtual int copyValueFrom(Tensor* tensor) = 0; + + const char* bool_to_str(bool in) const + { + static const char* true_str = "true"; + static const char* false_str = "false"; + return in ? true_str : false_str; + } + + virtual int allocate() = 0; + virtual int deallocate() = 0; + virtual bool is_allocated() = 0; + +protected: + std::string tensorName; + DType tensorDtype; + std::vector tensorUsage; + std::vector tensorFormat; + int isConst; + int isValid; + std::vector shape; + int isSubgraphInput; + int isSubgraphOutput; + bool isAllocated; + + GraphNode* producer; + std::vector consumers; + + // Note: the Eigen::Tensor is not declared in Tensor + // Instead, the TensorTemplate class keeps the templated tensor + // declaration so that the graph manipulation tools are isolated + // from the templated tensor type. + // + // Operators need to be aware of the TensorTemplate> type + // so that they can operate on the right types. +}; + +template +class TensorTemplate : public Tensor +{ +public: + TensorTemplate(std::string tensorName_, + DType tensorDtype_, + const std::vector& tensorUsage_, + const std::vector& tensorFormat_, + std::vector shape_, + int isConst_) + : Tensor(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, isConst_) + { + tensor = nullptr; + } + + virtual ~TensorTemplate() + { + deallocate(); + } + + virtual int allocate() + { + tensor = new T(); + if (tensor) + return 0; + else + return 1; + } + + virtual int deallocate() + { + if (tensor) + { + delete tensor; + } + tensor = nullptr; + return 0; + } + + virtual bool is_allocated() + { + if (tensor) + { + return true; + } + return false; + } + + T& getTensor() + { + return *tensor; + } + + virtual int dumpTensor(FILE* out) const; + + virtual int setTensorValueFloat(const size_t bufLen, const float* vals); + virtual int setTensorValueInt32(const size_t bufLen, const int32_t* vals); + virtual int setTensorValueInt64(const size_t bufLen, const int64_t* vals); + virtual int setTensorValueBool(const size_t bufLen, const bool* vals); + virtual int getTensorValueFloat(const size_t bufLen, float* fbuf) const; + virtual int getTensorValueInt32(const size_t bufLen, int32_t* ibuf) const; + virtual int getTensorValueInt64(const size_t bufLen, int64_t* ibuf) const; + virtual int getTensorValueBool(const size_t bufLen, bool* bbuf) const; + + virtual int copyValueFrom(Tensor* tensor); + +protected: + T* tensor; +}; + +// allocate() template specializations to allocate the different tensor sizes +// Let the compiler know here before the factory uses them, but define them in the .cc file. +template <> +int Tensor0::allocate(); +template <> +int Tensor1::allocate(); +template <> +int Tensor2::allocate(); +template <> +int Tensor3::allocate(); +template <> +int Tensor4::allocate(); +template <> +int Tensor5::allocate(); +template <> +int Tensor6::allocate(); + +template <> +int Tensor0::allocate(); +template <> +int Tensor1::allocate(); +template <> +int Tensor2::allocate(); +template <> +int Tensor3::allocate(); +template <> +int Tensor4::allocate(); +template <> +int Tensor5::allocate(); +template <> +int Tensor6::allocate(); + +template <> +int Tensor0::allocate(); +template <> +int Tensor1::allocate(); +template <> +int Tensor2::allocate(); +template <> +int Tensor3::allocate(); +template <> +int Tensor4::allocate(); +template <> +int Tensor5::allocate(); +template <> +int Tensor6::allocate(); + +template <> +int Tensor0::allocate(); +template <> +int Tensor1::allocate(); +template <> +int Tensor2::allocate(); +template <> +int Tensor3::allocate(); +template <> +int Tensor4::allocate(); +template <> +int Tensor5::allocate(); +template <> +int Tensor6::allocate(); + +template <> +int Tensor0::copyValueFrom(Tensor* src); +template <> +int Tensor1::copyValueFrom(Tensor* src); +template <> +int Tensor2::copyValueFrom(Tensor* src); +template <> +int Tensor3::copyValueFrom(Tensor* src); +template <> +int Tensor4::copyValueFrom(Tensor* src); +template <> +int Tensor5::copyValueFrom(Tensor* src); +template <> +int Tensor6::copyValueFrom(Tensor* src); + +template <> +int Tensor0::copyValueFrom(Tensor* src); +template <> +int Tensor1::copyValueFrom(Tensor* src); +template <> +int Tensor2::copyValueFrom(Tensor* src); +template <> +int Tensor3::copyValueFrom(Tensor* src); +template <> +int Tensor4::copyValueFrom(Tensor* src); +template <> +int Tensor5::copyValueFrom(Tensor* src); +template <> +int Tensor6::copyValueFrom(Tensor* src); + +template <> +int Tensor0::copyValueFrom(Tensor* src); +template <> +int Tensor1::copyValueFrom(Tensor* src); +template <> +int Tensor2::copyValueFrom(Tensor* src); +template <> +int Tensor3::copyValueFrom(Tensor* src); +template <> +int Tensor4::copyValueFrom(Tensor* src); +template <> +int Tensor5::copyValueFrom(Tensor* src); +template <> +int Tensor6::copyValueFrom(Tensor* src); + +template <> +int Tensor0::copyValueFrom(Tensor* src); +template <> +int Tensor1::copyValueFrom(Tensor* src); +template <> +int Tensor2::copyValueFrom(Tensor* src); +template <> +int Tensor3::copyValueFrom(Tensor* src); +template <> +int Tensor4::copyValueFrom(Tensor* src); +template <> +int Tensor5::copyValueFrom(Tensor* src); +template <> +int Tensor6::copyValueFrom(Tensor* src); + +template <> +int Tensor0::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor1::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor2::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor3::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor4::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor5::setTensorValueInt32(const size_t bufLen, const int32_t* vals); +template <> +int Tensor6::setTensorValueInt32(const size_t bufLen, const int32_t* vals); + +template <> +int Tensor0::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor1::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor2::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor3::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor4::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor5::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; +template <> +int Tensor6::getTensorValueInt32(const size_t bufLen, int32_t* vals) const; + +template <> +int Tensor0::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor1::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor2::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor3::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor4::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor5::setTensorValueInt64(const size_t bufLen, const int64_t* vals); +template <> +int Tensor6::setTensorValueInt64(const size_t bufLen, const int64_t* vals); + +template <> +int Tensor0::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor1::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor2::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor3::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor4::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor5::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; +template <> +int Tensor6::getTensorValueInt64(const size_t bufLen, int64_t* vals) const; + +template <> +int Tensor0::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor1::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor2::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor3::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor4::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor5::setTensorValueFloat(const size_t bufLen, const float* vals); +template <> +int Tensor6::setTensorValueFloat(const size_t bufLen, const float* vals); + +template <> +int Tensor0::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor1::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor2::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor3::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor4::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor5::getTensorValueFloat(const size_t bufLen, float* vals) const; +template <> +int Tensor6::getTensorValueFloat(const size_t bufLen, float* vals) const; + +template <> +int Tensor0::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor1::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor2::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor3::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor4::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor5::setTensorValueBool(const size_t bufLen, const bool* vals); +template <> +int Tensor6::setTensorValueBool(const size_t bufLen, const bool* vals); + +template <> +int Tensor0::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor1::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor2::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor3::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor4::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor5::getTensorValueBool(const size_t bufLen, bool* vals) const; +template <> +int Tensor6::getTensorValueBool(const size_t bufLen, bool* vals) const; + +// assume we only dump float type tensor now +template <> +int Tensor0::dumpTensor(FILE* out) const; +template <> +int Tensor1::dumpTensor(FILE* out) const; +template <> +int Tensor2::dumpTensor(FILE* out) const; +template <> +int Tensor3::dumpTensor(FILE* out) const; +template <> +int Tensor4::dumpTensor(FILE* out) const; +template <> +int Tensor5::dumpTensor(FILE* out) const; +template <> +int Tensor6::dumpTensor(FILE* out) const; +template <> +int Tensor0::dumpTensor(FILE* out) const; +template <> +int Tensor1::dumpTensor(FILE* out) const; +template <> +int Tensor2::dumpTensor(FILE* out) const; +template <> +int Tensor3::dumpTensor(FILE* out) const; +template <> +int Tensor4::dumpTensor(FILE* out) const; +template <> +int Tensor5::dumpTensor(FILE* out) const; +template <> +int Tensor6::dumpTensor(FILE* out) const; +template <> +int Tensor0::dumpTensor(FILE* out) const; +template <> +int Tensor1::dumpTensor(FILE* out) const; +template <> +int Tensor2::dumpTensor(FILE* out) const; +template <> +int Tensor3::dumpTensor(FILE* out) const; +template <> +int Tensor4::dumpTensor(FILE* out) const; +template <> +int Tensor5::dumpTensor(FILE* out) const; +template <> +int Tensor6::dumpTensor(FILE* out) const; +template <> +int Tensor0::dumpTensor(FILE* out) const; +template <> +int Tensor1::dumpTensor(FILE* out) const; +template <> +int Tensor2::dumpTensor(FILE* out) const; +template <> +int Tensor3::dumpTensor(FILE* out) const; +template <> +int Tensor4::dumpTensor(FILE* out) const; +template <> +int Tensor5::dumpTensor(FILE* out) const; +template <> +int Tensor6::dumpTensor(FILE* out) const; + +class TensorFactory +{ +public: + static Tensor* newTensor(std::string tensorName_, + DType tensorDtype_, + const std::vector& tensorUsage_, + const std::vector& tensorFormat_, + std::vector shape_, + int isConst_, + const uint32_t rank) + { + switch (tensorDtype_) + { + case DType_FLOAT: + switch (rank) + { + case 0: + return new Tensor0(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 1: + return new Tensor1(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 2: + return new Tensor2(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 3: + return new Tensor3(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 4: + return new Tensor4(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 5: + return new Tensor5(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 6: + return new Tensor6(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + default: + goto done; + } + case DType_INT32: + case DType_AINT8: + case DType_UINT8: + case DType_INT4: + case DType_INT8: + case DType_INT16: + switch (rank) + { + case 0: + return new Tensor0(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 1: + return new Tensor1(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 2: + return new Tensor2(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 3: + return new Tensor3(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 4: + return new Tensor4(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 5: + return new Tensor5(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 6: + return new Tensor6(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + default: + goto done; + } + case DType_INT48: + switch (rank) + { + case 0: + return new Tensor0(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 1: + return new Tensor1(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 2: + return new Tensor2(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 3: + return new Tensor3(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 4: + return new Tensor4(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 5: + return new Tensor5(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 6: + return new Tensor6(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + default: + goto done; + } + case DType_BOOL: + switch (rank) + { + case 0: + return new Tensor0(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 1: + return new Tensor1(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 2: + return new Tensor2(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 3: + return new Tensor3(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 4: + return new Tensor4(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 5: + return new Tensor5(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + case 6: + return new Tensor6(tensorName_, tensorDtype_, tensorUsage_, tensorFormat_, shape_, + isConst_); + default: + goto done; + } + default: + goto done; + } + + done: + FATAL_ERROR("Unsupported tensor name=%s, type=%s, rank=%d", tensorName_.c_str(), EnumNamesDType()[tensorDtype_], + rank); + } + + static Tensor* newTensor(DType type, const std::vector shape); +}; +}; // namespace TosaReference + +#endif -- cgit v1.2.1