blob: 012b9500049cd0ac651262e3b2a269ef9959023d [file] [log] [blame]
//
// Copyright © 2017 Arm Ltd. All rights reserved.
// SPDX-License-Identifier: MIT
//
#pragma once
#include "TensorFwd.hpp"
#include "Exceptions.hpp"
#include "Optional.hpp"
#include "Types.hpp"
#include <array>
#include <initializer_list>
#include <vector>
namespace armnn
{
class TensorShape
{
public:
/// Empty (invalid) constructor.
TensorShape();
TensorShape(unsigned int numDimensions);
TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes);
TensorShape(std::initializer_list<unsigned int> dimensionSizeList);
TensorShape(const TensorShape& other);
TensorShape& operator=(const TensorShape& other);
unsigned int operator[](unsigned int i) const;
unsigned int& operator[](unsigned int i);
bool operator==(const TensorShape& other) const;
bool operator!=(const TensorShape& other) const;
unsigned int GetNumDimensions() const { return m_NumDimensions; }
unsigned int GetNumElements() const;
private:
std::array<unsigned int, MaxNumOfTensorDimensions> m_Dimensions;
unsigned int m_NumDimensions;
void CheckDimensionIndex(unsigned int i) const;
};
class TensorInfo
{
public:
/// Empty (invalid) constructor.
TensorInfo();
TensorInfo(const TensorShape& shape,
DataType dataType,
float quantizationScale = 0.0f,
int32_t quantizationOffset = 0);
TensorInfo(unsigned int numDimensions,
const unsigned int* dimensionSizes,
DataType dataType,
float quantizationScale = 0.0f,
int32_t quantizationOffset = 0);
TensorInfo(const TensorShape& shape,
DataType dataType,
const std::vector<float>& quantizationScales,
unsigned int quantizationDim);
TensorInfo(unsigned int numDimensions,
const unsigned int* dimensionSizes,
DataType dataType,
const std::vector<float>& quantizationScales,
unsigned int quantizationDim);
TensorInfo(const TensorInfo& other);
TensorInfo& operator=(const TensorInfo& other);
bool operator==(const TensorInfo& other) const;
bool operator!=(const TensorInfo& other) const;
const TensorShape& GetShape() const { return m_Shape; }
TensorShape& GetShape() { return m_Shape; }
void SetShape(const TensorShape& newShape) { m_Shape = newShape; }
unsigned int GetNumDimensions() const { return m_Shape.GetNumDimensions(); }
unsigned int GetNumElements() const { return m_Shape.GetNumElements(); }
DataType GetDataType() const { return m_DataType; }
void SetDataType(DataType type) { m_DataType = type; }
bool HasMultipleQuantizationScales() const { return m_Quantization.m_Scales.size() > 1; }
bool HasPerAxisQuantization() const;
std::vector<float> GetQuantizationScales() const;
void SetQuantizationScales(const std::vector<float>& scales);
float GetQuantizationScale() const;
void SetQuantizationScale(float scale);
int32_t GetQuantizationOffset() const;
void SetQuantizationOffset(int32_t offset);
Optional<unsigned int> GetQuantizationDim() const;
void SetQuantizationDim(const Optional<unsigned int>& quantizationDim);
bool IsQuantized() const;
/// Check that the types are the same and, if quantize, that the quantization parameters are the same.
bool IsTypeSpaceMatch(const TensorInfo& other) const;
unsigned int GetNumBytes() const;
private:
TensorShape m_Shape;
DataType m_DataType;
/// Vectors of scale and offset are used for per-axis quantization.
struct Quantization
{
Quantization()
: m_Scales{}
, m_Offset(EmptyOptional())
, m_QuantizationDim(EmptyOptional()) {}
bool operator==(const Quantization& other) const
{
return ((m_Scales == other.m_Scales) && (m_Offset == other.m_Offset) &&
(m_QuantizationDim == other.m_QuantizationDim));
}
std::vector<float> m_Scales;
Optional<int32_t> m_Offset;
Optional<unsigned int> m_QuantizationDim;
} m_Quantization;
};
using BindingPointInfo = std::pair<armnn::LayerBindingId, armnn::TensorInfo>;
template<typename MemoryType>
class BaseTensor
{
public:
/// Empty (invalid) constructor.
BaseTensor();
/// Constructor from a raw memory pointer.
/// @param memoryArea - Region of CPU-addressable memory where tensor data will be stored. Must be valid while
/// workloads are on the fly. Tensor instances do not claim ownership of referenced memory regions, that is,
/// no attempt will be made by ArmNN to free these memory regions automatically.
BaseTensor(const TensorInfo& info, MemoryType memoryArea);
/// Tensors are copyable.
BaseTensor(const BaseTensor& other);
/// Tensors are copyable.
BaseTensor& operator=(const BaseTensor&);
const TensorInfo& GetInfo() const { return m_Info; }
TensorInfo& GetInfo() { return m_Info; }
const TensorShape& GetShape() const { return m_Info.GetShape(); }
TensorShape& GetShape() { return m_Info.GetShape(); }
DataType GetDataType() const { return m_Info.GetDataType(); }
unsigned int GetNumDimensions() const { return m_Info.GetNumDimensions(); }
unsigned int GetNumBytes() const { return m_Info.GetNumBytes(); }
unsigned int GetNumElements() const { return m_Info.GetNumElements(); }
MemoryType GetMemoryArea() const { return m_MemoryArea; }
protected:
/// Protected destructor to stop users from making these
/// (could still new one on the heap and then leak it...)
~BaseTensor() {}
MemoryType m_MemoryArea;
private:
TensorInfo m_Info;
};
/// A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
class Tensor : public BaseTensor<void*>
{
public:
/// Brings in the constructors and assignment operator.
using BaseTensor<void*>::BaseTensor;
};
/// A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
class ConstTensor : public BaseTensor<const void*>
{
public:
/// Brings in the constructors and assignment operator.
using BaseTensor<const void*>::BaseTensor;
ConstTensor() : BaseTensor<const void*>() {} // This needs to be redefined explicitly??
/// Can be implicitly constructed from non-const Tensor.
ConstTensor(const Tensor& other) : BaseTensor<const void*>(other.GetInfo(), other.GetMemoryArea()) {}
/// Constructor from a backing container.
/// @param container - An stl-like container type which implements data() and size() methods.
/// Presence of data() and size() is a strong indicator of the continuous memory layout of the container,
/// which is a requirement for Tensor data. Tensor instances do not claim ownership of referenced memory regions,
/// that is, no attempt will be made by ArmNN to free these memory regions automatically.
template < template<typename, typename...> class ContainerType, typename T, typename...ContainerArgs >
ConstTensor(const TensorInfo& info, const ContainerType<T, ContainerArgs...>& container)
: BaseTensor<const void*>(info, container.data())
{
if (container.size() * sizeof(T) != info.GetNumBytes())
{
throw InvalidArgumentException("Container size is not correct");
}
}
};
using InputTensors = std::vector<std::pair<LayerBindingId, class ConstTensor>>;
using OutputTensors = std::vector<std::pair<LayerBindingId, class Tensor>>;
} // namespace armnn