From 4fcda0101ec3d110c1d6d7bee5c83416b645528a Mon Sep 17 00:00:00 2001 From: telsoa01 Date: Fri, 9 Mar 2018 14:13:49 +0000 Subject: Release 18.02 Change-Id: Id3c11dc5ee94ef664374a988fcc6901e9a232fa6 --- include/armnn/ArmNN.hpp | 16 ++ include/armnn/Descriptors.hpp | 307 +++++++++++++++++++++++++++++++++++++++ include/armnn/DescriptorsFwd.hpp | 26 ++++ include/armnn/Exceptions.hpp | 75 ++++++++++ include/armnn/INetwork.hpp | 281 +++++++++++++++++++++++++++++++++++ include/armnn/IRuntime.hpp | 116 +++++++++++++++ include/armnn/LayerSupport.hpp | 140 ++++++++++++++++++ include/armnn/NetworkFwd.hpp | 16 ++ include/armnn/Tensor.hpp | 179 +++++++++++++++++++++++ include/armnn/TensorFwd.hpp | 15 ++ include/armnn/Types.hpp | 155 ++++++++++++++++++++ include/armnn/TypesUtils.hpp | 182 +++++++++++++++++++++++ include/armnn/Utils.hpp | 27 ++++ include/armnn/Version.hpp | 12 ++ 14 files changed, 1547 insertions(+) create mode 100644 include/armnn/ArmNN.hpp create mode 100644 include/armnn/Descriptors.hpp create mode 100644 include/armnn/DescriptorsFwd.hpp create mode 100644 include/armnn/Exceptions.hpp create mode 100644 include/armnn/INetwork.hpp create mode 100644 include/armnn/IRuntime.hpp create mode 100644 include/armnn/LayerSupport.hpp create mode 100644 include/armnn/NetworkFwd.hpp create mode 100644 include/armnn/Tensor.hpp create mode 100644 include/armnn/TensorFwd.hpp create mode 100644 include/armnn/Types.hpp create mode 100644 include/armnn/TypesUtils.hpp create mode 100644 include/armnn/Utils.hpp create mode 100644 include/armnn/Version.hpp (limited to 'include/armnn') diff --git a/include/armnn/ArmNN.hpp b/include/armnn/ArmNN.hpp new file mode 100644 index 0000000000..d1cb7a8488 --- /dev/null +++ b/include/armnn/ArmNN.hpp @@ -0,0 +1,16 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include "Descriptors.hpp" +#include "Exceptions.hpp" +#include "IRuntime.hpp" +#include "INetwork.hpp" +#include "LayerSupport.hpp" +#include "Tensor.hpp" +#include "Types.hpp" +#include "TypesUtils.hpp" +#include "Utils.hpp" +#include "Version.hpp" diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp new file mode 100644 index 0000000000..2595656c70 --- /dev/null +++ b/include/armnn/Descriptors.hpp @@ -0,0 +1,307 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include "DescriptorsFwd.hpp" + +#include +#include + +#include "Tensor.hpp" +#include "Types.hpp" + +namespace armnn +{ + +struct ActivationDescriptor +{ + ActivationDescriptor() : m_Function(ActivationFunction::Sigmoid), m_A(0), m_B(0) {}; + + ActivationFunction m_Function; + float m_A; + float m_B; +}; + +struct PermuteDescriptor +{ + PermuteDescriptor() + : m_DimMappings{} + { + } + PermuteDescriptor(const PermutationVector& dimMappings) + : m_DimMappings(dimMappings) + { + } + + PermutationVector m_DimMappings; +}; + +struct SoftmaxDescriptor +{ + SoftmaxDescriptor() : m_Beta(1.0f) {}; + + float m_Beta; +}; + + +struct OriginsDescriptor +{ + OriginsDescriptor(); + OriginsDescriptor(uint32_t numViews, uint32_t numDimensions = 4); + OriginsDescriptor(const OriginsDescriptor& other); + OriginsDescriptor(OriginsDescriptor&& other); + + ~OriginsDescriptor(); + + OriginsDescriptor& operator=(OriginsDescriptor rhs); + + Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value); + uint32_t GetNumViews() const; + uint32_t GetNumDimensions() const; + const uint32_t* GetViewOrigin(uint32_t idx) const; + void ReorderOrigins(unsigned int* newOrdering, unsigned int numNewOrdering); + friend void swap(OriginsDescriptor& first, OriginsDescriptor& second); + +private: + uint32_t m_NumViews; + uint32_t m_NumDimensions; + uint32_t** m_ViewOrigins; +}; + +struct ViewsDescriptor +{ + ViewsDescriptor(uint32_t numViews, uint32_t numDimensions = 4); + ViewsDescriptor(const ViewsDescriptor& other); + ViewsDescriptor(); + ViewsDescriptor(ViewsDescriptor&& other); + + ~ViewsDescriptor(); + + ViewsDescriptor& operator=(ViewsDescriptor rhs); + + Status SetViewOriginCoord(uint32_t view, uint32_t coord, uint32_t value); + Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value); + + uint32_t GetNumViews() const; + uint32_t GetNumDimensions() const; + const uint32_t* GetViewOrigin(uint32_t idx) const; + const uint32_t* GetViewSizes(uint32_t idx) const; + + friend void swap(ViewsDescriptor& first, ViewsDescriptor& second); +private: + OriginsDescriptor m_Origins; + uint32_t** m_ViewSizes; +}; + +// Convenience template to create a OriginsDescriptor to use when creating a Merger layer for performing concatenation +// of a number of input tensors +template +OriginsDescriptor CreateMergerDescriptorForConcatenation(TensorShapeIt first, TensorShapeIt last, + unsigned int concatenationDimension) +{ + auto numInputs = std::distance(first, last); + + if (numInputs < 2) + { + throw InvalidArgumentException("Concatenation requires at least 2 inputs"); + } + + const auto& firstInputShape = *first; + + const unsigned int numDimensions = firstInputShape.GetNumDimensions(); + for (auto it = first + 1; it != last; ++it) + { + if (it->GetNumDimensions() != numDimensions) + { + throw InvalidArgumentException("All inputs to concatenation must have the same number of dimensions"); + } + } + + if (concatenationDimension >= numDimensions) + { + throw InvalidArgumentException("concatenationDimension must be between 0 and the number of dimensions."); + } + + for (auto it = first; it != last; ++it) + { + for (unsigned int d = 0; d < numDimensions; ++d) + { + const bool dimSizeOk = (d == concatenationDimension) || (firstInputShape[d] == (*it)[d]); + if (!dimSizeOk) + { + throw InvalidArgumentException("All inputs to concatenation must be the same size along all dimensions " + " except the concatenation dimension"); + } + } + } + + OriginsDescriptor viewsDescriptor(static_cast(numInputs), numDimensions); + + uint32_t viewIndex = 0u; + uint32_t coordAlongConcatDim = 0u; + for (auto it = first; it != last; ++it) + { + const auto& inputShape = *it; + + for (unsigned int i = 0; i < concatenationDimension; ++i) + { + viewsDescriptor.SetViewOriginCoord(viewIndex, i, 0); + } + + viewsDescriptor.SetViewOriginCoord(viewIndex, concatenationDimension, coordAlongConcatDim); + unsigned int dimSize = inputShape[concatenationDimension]; + coordAlongConcatDim += dimSize; + + + for (unsigned int i = concatenationDimension + 1; i < numDimensions; ++i) + { + viewsDescriptor.SetViewOriginCoord(viewIndex, i, 0); + } + + ++viewIndex; + } + + return viewsDescriptor; +} + +struct Pooling2dDescriptor +{ + Pooling2dDescriptor() + : m_PoolType(PoolingAlgorithm::Max) + , m_PadLeft(0) + , m_PadRight(0) + , m_PadTop(0) + , m_PadBottom(0) + , m_PoolWidth(0) + , m_PoolHeight(0) + , m_StrideX(0) + , m_StrideY(0) + , m_OutputShapeRounding(OutputShapeRounding::Floor) + , m_PaddingMethod(PaddingMethod::Exclude) + {}; + + PoolingAlgorithm m_PoolType; + uint32_t m_PadLeft; + uint32_t m_PadRight; + uint32_t m_PadTop; + uint32_t m_PadBottom; + uint32_t m_PoolWidth; + uint32_t m_PoolHeight; + uint32_t m_StrideX; + uint32_t m_StrideY; + OutputShapeRounding m_OutputShapeRounding; + PaddingMethod m_PaddingMethod; +}; + +struct FullyConnectedDescriptor +{ + FullyConnectedDescriptor() + : m_BiasEnabled(false) + , m_TransposeWeightMatrix(false) + {}; + + bool m_BiasEnabled; + bool m_TransposeWeightMatrix; +}; + +struct Convolution2dDescriptor +{ + Convolution2dDescriptor() + : m_PadLeft(0) + , m_PadRight(0) + , m_PadTop(0) + , m_PadBottom(0) + , m_StrideX(0) + , m_StrideY(0) + , m_BiasEnabled(false) + {}; + + uint32_t m_PadLeft; + uint32_t m_PadRight; + uint32_t m_PadTop; + uint32_t m_PadBottom; + uint32_t m_StrideX; + uint32_t m_StrideY; + bool m_BiasEnabled; +}; + +struct DepthwiseConvolution2dDescriptor +{ + DepthwiseConvolution2dDescriptor() + : m_PadLeft(0) + , m_PadRight(0) + , m_PadTop(0) + , m_PadBottom(0) + , m_StrideX(0) + , m_StrideY(0) + , m_BiasEnabled(false) + {} + + uint32_t m_PadLeft; + uint32_t m_PadRight; + uint32_t m_PadTop; + uint32_t m_PadBottom; + uint32_t m_StrideX; + uint32_t m_StrideY; + bool m_BiasEnabled; +}; + + +struct NormalizationDescriptor +{ + NormalizationDescriptor() + : m_NormChannelType(NormalizationAlgorithmChannel::Across) + , m_NormMethodType(NormalizationAlgorithmMethod::LocalBrightness) + , m_NormSize(0) + , m_Alpha(0.f) + , m_Beta(0.f) + , m_K(0.f) + {} + + NormalizationAlgorithmChannel m_NormChannelType; + NormalizationAlgorithmMethod m_NormMethodType; + uint32_t m_NormSize; + float m_Alpha; + float m_Beta; + float m_K; +}; + +struct BatchNormalizationDescriptor +{ + BatchNormalizationDescriptor() + : m_Eps(0.0001f) + {} + + float m_Eps; +}; + +struct FakeQuantizationDescriptor +{ + FakeQuantizationDescriptor() + : m_Min(-6.0f) + , m_Max(6.0f) + {} + + float m_Min; + float m_Max; +}; + +struct ResizeBilinearDescriptor +{ + ResizeBilinearDescriptor() + : m_TargetWidth(0) + , m_TargetHeight(0) + {} + + uint32_t m_TargetWidth; + uint32_t m_TargetHeight; +}; + +struct ReshapeDescriptor +{ + TensorShape m_TargetShape; +}; + +} diff --git a/include/armnn/DescriptorsFwd.hpp b/include/armnn/DescriptorsFwd.hpp new file mode 100644 index 0000000000..58b4bcc626 --- /dev/null +++ b/include/armnn/DescriptorsFwd.hpp @@ -0,0 +1,26 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +namespace armnn +{ +struct ActivationDescriptor; +struct BatchNormalizationDescriptor; +struct Convolution2dDescriptor; +struct DepthwiseConvolution2dDescriptor; +struct FakeQuantizationDescriptor; +struct FullyConnectedDescriptor; +struct PermuteDescriptor; +struct NormalizationDescriptor; +struct Pooling2dDescriptor; +struct ReshapeDescriptor; +struct ResizeBilinearDescriptor; +struct SoftmaxDescriptor; +struct OriginsDescriptor; +struct ViewsDescriptor; + +using MergerDescriptor = OriginsDescriptor; +using SplitterDescriptor = ViewsDescriptor; +} diff --git a/include/armnn/Exceptions.hpp b/include/armnn/Exceptions.hpp new file mode 100644 index 0000000000..0b043997c4 --- /dev/null +++ b/include/armnn/Exceptions.hpp @@ -0,0 +1,75 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include +#include + +namespace armnn +{ + +// base class for all ArmNN exceptions so that users can filter to just those +class Exception : public std::exception +{ +public: + explicit Exception(const std::string& message); + + virtual const char* what() const noexcept override; + +private: + std::string m_Message; +}; + +class ClRuntimeUnavailableException : public Exception +{ +public: + using Exception::Exception; +}; + +class InvalidArgumentException : public Exception +{ +public: + using Exception::Exception; +}; + +class FileNotFoundException : public Exception +{ +public: + using Exception::Exception; +}; + +class ParseException : public Exception +{ +public: + using Exception::Exception; +}; + +class UnimplementedException : public Exception +{ +public: + using Exception::Exception; + UnimplementedException(); +}; + +class LayerValidationException : public Exception +{ + using Exception::Exception; +}; + +class GraphValidationException : public Exception +{ + using Exception::Exception; +}; + +template +void ConditionalThrow(bool condition, const std::string& message) +{ + if (!condition) + { + throw ExceptionType(message); + } +} + +} diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp new file mode 100644 index 0000000000..8545629c96 --- /dev/null +++ b/include/armnn/INetwork.hpp @@ -0,0 +1,281 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include "armnn/NetworkFwd.hpp" +#include "armnn/DescriptorsFwd.hpp" +#include "armnn/TensorFwd.hpp" + +#include "armnn/Types.hpp" + +#include + +namespace armnn +{ + +/// @brief An input connection slot for a layer. +/// The input slot can be connected to an output slot of the preceding layer in the graph. +/// Only one connection to the input slot is allowed. +class IInputSlot +{ +public: + virtual const IOutputSlot* GetConnection() const = 0; + virtual IOutputSlot* GetConnection() = 0; + +protected: + ~IInputSlot() {} /// Not user deletable +}; + +/// @brief An output connection slot for a layer. +/// The output slot may be connected to 1 or more input slots of subsequent layers in the graph. +class IOutputSlot +{ +public: + virtual unsigned int GetNumConnections() const = 0; + virtual const IInputSlot* GetConnection(unsigned int index) const = 0; + virtual IInputSlot* GetConnection(unsigned int index) = 0; + + virtual void SetTensorInfo(const TensorInfo& tensorInfo) = 0; + virtual const TensorInfo& GetTensorInfo() const = 0; + virtual bool IsTensorInfoSet() const = 0; + + virtual int Connect(IInputSlot& destination) = 0; + virtual void Disconnect(IInputSlot& slot) = 0; + +protected: + ~IOutputSlot() {} /// Not user deletable +}; + +/// @brief Interface for a layer that is connectable to other layers via InputSlots and OutputSlots. +class IConnectableLayer +{ +public: + virtual const char* GetName() const = 0; + + virtual unsigned int GetNumInputSlots() const = 0; + virtual unsigned int GetNumOutputSlots() const = 0; + + virtual const IInputSlot& GetInputSlot(unsigned int index) const = 0; + virtual IInputSlot& GetInputSlot(unsigned int index) = 0; + + virtual const IOutputSlot& GetOutputSlot(unsigned int index) const = 0; + virtual IOutputSlot& GetOutputSlot(unsigned int index) = 0; + +protected: + ~IConnectableLayer() {} // Objects are not deletable via the handle +}; + +using INetworkPtr = std::unique_ptr; + +/// Main network class which provides the interface for building up a neural network. +/// This object is subsequently required by the IRuntime::Load() method. +class INetwork +{ +public: + static INetwork* CreateRaw(); + static INetworkPtr Create(); + static void Destroy(INetwork* network); + + virtual Status PrintGraph() = 0; + + /// Add an input layer to the network. + /// @param id User generated id to uniquely identify a particular input. The same id needs to be specified + /// when passing the inputs to the IRuntime::EnqueueWorkload() function. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddInputLayer(LayerBindingId id, const char* name = nullptr) = 0; + + /// Add a 2D convolution layer to the network. + /// @param convolution2dDescriptor Description of the 2D convolution layer + /// @param weights Tensor for the weights data. + /// @param biases (Optional) Tensor for the bias data. Must match the output tensor shape. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, + const ConstTensor& weights, + const char* name = nullptr) = 0; + + virtual IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, + const ConstTensor& weights, + const ConstTensor& biases, + const char* name = nullptr) = 0; + + /// Add a 2D depthwise convolution layer to the network. + /// @param convolution2dDescriptor Description of the 2D depthwise convolution layer + /// @param weights Tensor for the weights data. Expected format: [1, outputChannels, height, width] + /// @param biases (Optional) Tensor for the bias data. Must match the output tensor shape. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddDepthwiseConvolution2dLayer( + const DepthwiseConvolution2dDescriptor& convolution2dDescriptor, + const ConstTensor& weights, + const char* name = nullptr) = 0; + + virtual IConnectableLayer* AddDepthwiseConvolution2dLayer( + const DepthwiseConvolution2dDescriptor& convolution2dDescriptor, + const ConstTensor& weights, + const ConstTensor& biases, + const char* name = nullptr) = 0; + + /// Add a fully connected layer to the network. + /// @param fullyConnectedDescriptor Description of the fully connected layer + /// @param weights Tensor for the weights data. + /// @param biases (Optional) Tensor for the bias data. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const ConstTensor& weights, + const char* name = nullptr) = 0; + + virtual IConnectableLayer* AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const ConstTensor& weights, + const ConstTensor& biases, + const char* name = nullptr) = 0; + + /// Add a permute layer to the network. + /// @param permuteDescriptor PermuteDescriptor to configure the permute + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddPermuteLayer(const PermuteDescriptor& permuteDescriptor, + const char* name = nullptr) = 0; + + /// Add a pooling layer to the network. + /// @param pooling2dDescriptor Pooling2dDescriptor to configure the pooling + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddPooling2dLayer(const Pooling2dDescriptor& pooling2dDescriptor, + const char* name = nullptr) = 0; + + /// Add an activation layer to the network. + /// @param activationDescriptor ActivationDescriptor to configure the activation + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddActivationLayer(const ActivationDescriptor& activationDescriptor, + const char* name = nullptr) = 0; + + /// Add a normalization layer to the network. + /// @param normalizationDescriptor NormalizationDescriptor to configure the normalization + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddNormalizationLayer(const NormalizationDescriptor& normalizationDescriptor, + const char* name = nullptr) = 0; + + /// Add a softmax layer to the network. + /// @param softmaxDescriptor SoftmaxDescriptor to configure the softmax + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddSoftmaxLayer(const SoftmaxDescriptor& softmaxDescriptor, + const char* name = nullptr) = 0; + + /// Add a splitter layer to the network. + /// @param splitterDescriptor WindowsDescriptor to configure the splitting process. Number of Views must be equal to + /// the number of outputs, and their order must match - e.g. first view corresponds to + /// the first output, second view to the second output, etc.... + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddSplitterLayer(const ViewsDescriptor& splitterDescriptor + , const char* name = nullptr) = 0; + + /// Add a merger layer to the network. + /// @param mergerDescriptor WindowsDescriptor to configure the merging process. Number of Views must be equal to + /// the number of inputs, and their order must match - e.g. first view corresponds to + /// the first input, second view to the second input, etc.... + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddMergerLayer(const OriginsDescriptor& mergerDescriptor, + const char* name = nullptr) = 0; + + /// Add an addition layer to the network. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddAdditionLayer(const char* name = nullptr) = 0; + + /// Add a multiplication layer to the network. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddMultiplicationLayer(const char* name = nullptr) = 0; + + /// Add a batch normalization layer to the network. + /// @param mean Pre-calculated mean for each channel + /// @param variance Pre-calculated variance for each channel + /// @param beta Per-channel additive factor + /// @param gamma Per-channel multiplicative factor + /// @return Interface for configuring the layer. + /// @param name Optional name for the layer + virtual IConnectableLayer* AddBatchNormalizationLayer(const BatchNormalizationDescriptor& desc, + const ConstTensor& mean, + const ConstTensor& variance, + const ConstTensor& beta, + const ConstTensor& gamma, + const char* name = nullptr) = 0; + + /// Add a resize bilinear layer to the network. + /// @param resizeDesc Parameters for the resize operation + /// @param name Optional name for the layer + /// @return Interface for configuring the layer + virtual IConnectableLayer* AddResizeBilinearLayer(const ResizeBilinearDescriptor& resizeDesc, + const char* name = nullptr) = 0; + + /// Add an L2 normalization layer to the network. + /// Normalization is performed along dimension 1, but requires a 4d input. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer + virtual IConnectableLayer* AddL2NormalizationLayer(const char* name = nullptr) = 0; + + /// Adds a layer with no inputs and a single output, which always corresponds to + /// the passed in constant tensor. + /// @param input Tensor to be provided as the only output of the layer. The layer will maintain its own copy of the + /// tensor data, meaning the memory referenced by @a input can be freed or reused after this function is + /// called. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer + virtual IConnectableLayer* AddConstantLayer(const ConstTensor& input, + const char* name = nullptr) = 0; + + /// Add a reshape layer to the network. + /// @param reshapeDescriptor Parameters for the reshape operation + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddReshapeLayer(const ReshapeDescriptor& reshapeDescriptor, + const char* name = nullptr) = 0; + + /// Add a floor layer to the network. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddFloorLayer(const char* name = nullptr) = 0; + + /// Add an output layer to the network. + /// @param id User generated id to uniquely identify a particular output. The same id needs to be specified + /// when passing the outputs to the IRuntime::EnqueueWorkload() function. + /// @param name Optional name for the layer + /// @return Interface for configuring the layer. + virtual IConnectableLayer* AddOutputLayer(LayerBindingId id, const char* name = nullptr) = 0; + +protected: + ~INetwork() {} +}; + +using IOptimizedNetworkPtr = std::unique_ptr; + +class IOptimizedNetwork +{ +public: + static void Destroy(IOptimizedNetwork* network); + + virtual Status PrintGraph() = 0; + +protected: + ~IOptimizedNetwork() {} +}; + + +/// Create an optimized version of the network +/// @param network INetwork description of the network to be optimized. +/// @param deviceSpec The choice of the default computation backend. +/// @return An IOptimizedNetworkPtr interface to the optimized network, throws an exception derived from +/// armnn::Exception if process fails. +IOptimizedNetworkPtr Optimize(const INetwork& network, const DeviceSpec& deviceSpec); + +} //namespace armnn diff --git a/include/armnn/IRuntime.hpp b/include/armnn/IRuntime.hpp new file mode 100644 index 0000000000..a1a3f0fda9 --- /dev/null +++ b/include/armnn/IRuntime.hpp @@ -0,0 +1,116 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include + +#include "Types.hpp" +#include "Tensor.hpp" +#include "INetwork.hpp" +#include "TypesUtils.hpp" + +namespace armnn +{ + +using NetworkId = int; + +class IClTunedParameters; + +class IRuntime; +using IRuntimePtr = std::unique_ptr; + +class IRuntime +{ +public: + struct CreationOptions + { + Compute m_DefaultComputeDevice; + bool m_UseCpuRefAsFallback; + /// If set, uses the CL tuned parameters from the given object when executing CL workloads. + /// It will also be updated with new tuned parameters if it is configured to do so. + IClTunedParameters* m_ClTunedParameters; + + CreationOptions(Compute defaultComputeDevice) + : m_DefaultComputeDevice(defaultComputeDevice) + , m_UseCpuRefAsFallback(true) + , m_ClTunedParameters(nullptr) + { + } + }; + + static IRuntime* CreateRaw(const CreationOptions& options); + static IRuntimePtr Create(const CreationOptions& options); + static void Destroy(IRuntime* runtime); + + /// Load a complete network into the IRuntime. + /// @param [out] networkIdOut Unique identifier for the network is returned in this reference. + /// @param [in] network Complete network to load into the IRuntime. + /// The runtime takes ownership of the network once passed in. + /// @return armnn::Status + virtual Status LoadNetwork(NetworkId& networkIdOut, IOptimizedNetworkPtr network) = 0; + + virtual TensorInfo GetInputTensorInfo(NetworkId networkId, LayerBindingId layerId) const = 0; + virtual TensorInfo GetOutputTensorInfo(NetworkId networkId, LayerBindingId layerId) const = 0; + + // Evaluate network using input in inputTensors, outputs filled into outputTensors + virtual Status EnqueueWorkload(NetworkId networkId, + const InputTensors& inputTensors, + const OutputTensors& outputTensors) = 0; + + /// Unload a network from the IRuntime. + /// At the moment this only removes the network from the m_Impl->m_Network. + /// This might need more work in the future to be AndroidNN compliant. + /// @param [in] networkId Unique identifier for the network to be unloaded. Generated in LoadNetwork(). + /// @return armnn::Status + virtual Status UnloadNetwork(NetworkId networkId) = 0; + + virtual const DeviceSpec& GetDeviceSpec() const = 0; + +protected: + ~IRuntime() {} +}; + +using IClTunedParametersPtr = std::unique_ptr; + +/// Manages a set of Open CL parameters which have been tuned for maximum performance. +/// Pass an instance of this object to the IRuntime::Create() method (via IRuntime::CreationOptions) to use it +/// for all CL workload execution. +/// +/// Can be created in two modes: +/// - In UseTunedParameters mode the parameters stored in this object are used to execute CL workloads. +/// - In UpdateTunedParameters mode, additionally, whenever a CL workload is executed for the first time the +/// optimum parameters will be found and stored in this object. WARNING - This tuning can be slow. +/// +/// The parameters can be loaded from and saved to a file so that you first run a slow initial read-write +/// execution, save the parameters for later and then run fast read-only executions using the optimised parameters. +class IClTunedParameters +{ +public: + enum class Mode + { + UseTunedParameters, + UpdateTunedParameters + }; + + /// Creates an IClTunedParameters with the given mode. + /// @{ + static IClTunedParameters* CreateRaw(Mode mode); + static IClTunedParametersPtr Create(Mode mode); + /// @} + static void Destroy(IClTunedParameters* params); + + /// Loads an existing set of tuned parameters from the given file. + /// If there is an error loading the file, an armnn::Exception is thrown. + virtual void Load(const char* filename) = 0; + + /// Saves the current set of tuned parameters to the given file. + /// If there is an error saving to the file, an armnn::Exception is thrown. + virtual void Save(const char* filename) const = 0; + +protected: + virtual ~IClTunedParameters() {}; +}; + +} diff --git a/include/armnn/LayerSupport.hpp b/include/armnn/LayerSupport.hpp new file mode 100644 index 0000000000..d9de76f89c --- /dev/null +++ b/include/armnn/LayerSupport.hpp @@ -0,0 +1,140 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include +#include +#include + +namespace armnn +{ + +bool IsActivationSupported(Compute compute, + const TensorInfo& input, + const ActivationDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsAdditionSupported(Compute compute, + const TensorInfo& input0, + const TensorInfo& input1, + const TensorInfo& output, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsBatchNormalizationSupported(Compute compute, + const TensorInfo& input, + const BatchNormalizationDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsConstantSupported(Compute compute, + const TensorInfo& output, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsConvolution2dSupported(Compute compute, + const TensorInfo& input, + const Convolution2dDescriptor& descriptor, + const TensorInfo& weights, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsDepthwiseConvolutionSupported(Compute compute, + const TensorInfo& input, + const DepthwiseConvolution2dDescriptor& descriptor, + const TensorInfo& weights, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsInputSupported(Compute compute, + const TensorInfo& input, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsFullyConnectedSupported(Compute compute, + const TensorInfo& input,const + FullyConnectedDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsL2NormalizationSupported(Compute compute, + const TensorInfo& input, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsMergerSupported(Compute compute, + const std::vector inputs, + const OriginsDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsMultiplicationSupported(Compute compute, + const TensorInfo& input0, + const TensorInfo& input1, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsNormalizationSupported(Compute compute, + const TensorInfo& input, + const TensorInfo& output, + const NormalizationDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsOutputSupported(Compute compute, + const TensorInfo& output, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsPermuteSupported(Compute compute, + const TensorInfo& input, + const TensorInfo& output, + const PermuteDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsPooling2dSupported(Compute compute, + const TensorInfo& input, + const TensorInfo& output, + const Pooling2dDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsResizeBilinearSupported(Compute compute, + const TensorInfo& input, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsSoftmaxSupported(Compute compute, + const TensorInfo& input, + const SoftmaxDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsSplitterSupported(Compute compute, + const TensorInfo& input, + const ViewsDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsFakeQuantizationSupported(Compute compute, + const TensorInfo& input, + const FakeQuantizationDescriptor& descriptor, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsReshapeSupported(Compute compute, + const TensorInfo& input, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +bool IsFloorSupported(Compute compute, + const TensorInfo& input, + const TensorInfo& output, + char* reasonIfUnsupported = nullptr, + size_t reasonIfUnsupportedMaxLength = 1024); + +} diff --git a/include/armnn/NetworkFwd.hpp b/include/armnn/NetworkFwd.hpp new file mode 100644 index 0000000000..75667fdfd0 --- /dev/null +++ b/include/armnn/NetworkFwd.hpp @@ -0,0 +1,16 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +namespace armnn +{ +class INetwork; +class IOptimizedNetwork; +class Graph; +class IInputSlot; +class IOutputSlot; +class IConnectableLayer; +class IDataLayer; +} \ No newline at end of file diff --git a/include/armnn/Tensor.hpp b/include/armnn/Tensor.hpp new file mode 100644 index 0000000000..910278f33f --- /dev/null +++ b/include/armnn/Tensor.hpp @@ -0,0 +1,179 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once +#include "TensorFwd.hpp" + +#include "Types.hpp" +#include "Exceptions.hpp" + +#include +#include +#include + +namespace armnn +{ + +class TensorShape +{ +public: + /// Empty (invalid) constructor + TensorShape(); + + TensorShape(unsigned int numDimensions, const unsigned int* dimensionSizes); + + TensorShape(std::initializer_list dimensionSizeList); + + TensorShape(const TensorShape& other); + + TensorShape& operator=(const TensorShape& other); + + unsigned int operator[](unsigned int i) const + { + return m_Dimensions.at(i); + } + + unsigned int& operator[](unsigned int i) + { + return m_Dimensions.at(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 m_Dimensions; + unsigned int m_NumDimensions; +}; + +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 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; } + + float GetQuantizationScale() const { return m_Quantization.m_Scale; } + int32_t GetQuantizationOffset() const { return m_Quantization.m_Offset; } + void SetQuantizationScale(float scale) { m_Quantization.m_Scale = scale; } + void SetQuantizationOffset(int32_t offset) { m_Quantization.m_Offset = offset; } + + unsigned int GetNumBytes() const; + +private: + TensorShape m_Shape; + DataType m_DataType; + /// Scale and offset values used for quantization + struct Quantization + { + Quantization() : m_Scale(0.f), m_Offset(0) {} + bool operator==(const Quantization& o) const {return ((m_Scale == o.m_Scale) && (m_Offset == o.m_Offset));} + float m_Scale; + int32_t m_Offset; + } m_Quantization; +}; + +template +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 +{ +public: + using BaseTensor::BaseTensor; // Bring in the constructors and assignment operator +}; + +/// A tensor defined by a TensorInfo (shape and data type) and an immutable backing store. +class ConstTensor : public BaseTensor +{ +public: + using BaseTensor::BaseTensor; // Bring in the constructors and assignment operator + ConstTensor() : BaseTensor() {} // This needs to be redefined explicitly?? + + // Can be implicitly constructed from non-const Tensor + ConstTensor(const Tensor& other) : BaseTensor(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 class ContainerType, typename T, typename...ContainerArgs > + ConstTensor(const TensorInfo& info, const ContainerType& container) + : BaseTensor(info, container.data()) + { + if (container.size() * sizeof(T) != info.GetNumBytes()) + { + throw InvalidArgumentException("Container size is not correct"); + } + } +}; + +using InputTensors = std::vector>; +using OutputTensors = std::vector>; + +} // namespace armnn diff --git a/include/armnn/TensorFwd.hpp b/include/armnn/TensorFwd.hpp new file mode 100644 index 0000000000..5ea035c877 --- /dev/null +++ b/include/armnn/TensorFwd.hpp @@ -0,0 +1,15 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +namespace armnn +{ + +class TensorShape; +class TensorInfo; +class Tensor; +class ConstTensor; + +} diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp new file mode 100644 index 0000000000..e1aa393ecc --- /dev/null +++ b/include/armnn/Types.hpp @@ -0,0 +1,155 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include + +namespace armnn +{ + +constexpr unsigned int MaxNumOfTensorDimensions = 4U; + +/// @enum Status enumeration +/// @var Status::Successful +/// @var Status::Failure +enum class Status +{ + Success = 0, + Failure = 1 +}; + +enum class DataType +{ + Float32 = 0, + QuantisedAsymm8 = 1, + Signed32 = 2 +}; + +enum class ActivationFunction +{ + Sigmoid = 0, + TanH = 1, + Linear = 2, + ReLu = 3, + BoundedReLu = 4, //< min(a, max(b, input)) + SoftReLu = 5, + LeakyReLu = 6, + Abs = 7, + Sqrt = 8, + Square = 9 +}; + +enum class PoolingAlgorithm +{ + Max = 0, + Average = 1, + L2 = 2 +}; + +/// +/// The padding method modifies the output of pooling layers. +/// In both supported methods, the values are ignored (they are +/// not even zeros which would make a difference for max pooling +/// a tensor with negative values). The difference between +/// IgnoreValue and Exclude is that the former count the padding +/// fields in the divisor of Average and L2 pooling, while +/// Exclude does not. +/// +enum class PaddingMethod +{ + IgnoreValue = 0, // The padding fields count, but ignored + Exclude = 1 // The padding fields don't count and ignored +}; + +enum class NormalizationAlgorithmChannel +{ + Across = 0, + Within = 1 +}; + +enum class NormalizationAlgorithmMethod +{ + LocalBrightness = 0, /* Krichevsky 2012: Local Brightness Normalization */ + LocalContrast = 1 /* Jarret 2009: Local Contrast Normalization */ +}; + +enum class OutputShapeRounding +{ + Floor = 0, + Ceiling = 1 +}; + +enum class Compute +{ + CpuRef = 0, // CPU Execution: Reference C++ kernels + CpuAcc = 1, // CPU Execution: NEON: ArmCompute + GpuAcc = 2, // GPU Execution: OpenCL: ArmCompute + Undefined = 5 +}; + +struct DeviceSpec +{ + Compute DefaultComputeDevice; +}; + +/// Type of identifiers for bindable layers (inputs, outputs). +using LayerBindingId = int; + +class PermutationVector +{ +public: + using ValueType = unsigned int; + using SizeType = unsigned int; + using ArrayType = std::array; + using ConstIterator = typename ArrayType::const_iterator; + + /// @param dimMappings Indicates how to translate tensor elements from a given source into the target destination, + /// when source and target potentially have different memory layouts. + /// + /// E.g. For a 4-d tensor laid out in memory with format (Batch Element, Height, Width, Channels), + /// which is to be passed as an input to ArmNN, each source dimension is mapped to the corresponding + /// ArmNN dimension. The Batch dimension remains the same (0 -> 0). The source Height dimension is mapped + /// to the location of the ArmNN Height dimension (1 -> 2). Similar arguments are made for the Width and + /// Channels (2 -> 3 and 3 -> 1). This will lead to @ref m_DimMappings pointing to the following array: + /// [ 0, 2, 3, 1 ]. + /// + /// Note that the mapping should be reversed if considering the case of ArmNN 4-d outputs (Batch Element, + /// Channels, Height, Width) being written to a destination with the format mentioned above. We now have + /// 0 -> 0, 2 -> 1, 3 -> 2, 1 -> 3, which, when reordered, lead to the following @ref m_DimMappings contents: + /// [ 0, 3, 1, 2 ]. + /// + PermutationVector(const ValueType *dimMappings, SizeType numDimMappings); + + PermutationVector(std::initializer_list dimMappings); + + ValueType operator[](SizeType i) const { return m_DimMappings.at(i); } + + SizeType GetSize() const { return m_NumDimMappings; } + + ConstIterator begin() const { return m_DimMappings.begin(); } + ConstIterator end() const { return m_DimMappings.end(); } + + bool IsEqual(const PermutationVector& other) const + { + return std::equal(begin(), end(), other.begin(), other.end()); + } + + bool IsInverse(const PermutationVector& other) const + { + bool isInverse = (GetSize() == other.GetSize()); + for (SizeType i = 0; isInverse && (i < GetSize()); ++i) + { + isInverse = (m_DimMappings[other.m_DimMappings[i]] == i); + } + return isInverse; + } + +private: + ArrayType m_DimMappings; + /// Number of valid entries in @ref m_DimMappings + SizeType m_NumDimMappings; +}; + +} diff --git a/include/armnn/TypesUtils.hpp b/include/armnn/TypesUtils.hpp new file mode 100644 index 0000000000..a851b66b28 --- /dev/null +++ b/include/armnn/TypesUtils.hpp @@ -0,0 +1,182 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +#include "Types.hpp" +#include +#include +#include +#include + +namespace armnn +{ + +constexpr char const* GetStatusAsCString(Status compute) +{ + switch (compute) + { + case armnn::Status::Success: return "Status::Success"; + case armnn::Status::Failure: return "Status::Failure"; + default: return "Unknown"; + } +} + +constexpr char const* GetComputeDeviceAsCString(Compute compute) +{ + switch (compute) + { + case armnn::Compute::CpuRef: return "CpuRef"; + case armnn::Compute::CpuAcc: return "CpuAcc"; + case armnn::Compute::GpuAcc: return "GpuAcc"; + default: return "Unknown"; + } +} + +constexpr unsigned int GetDataTypeSize(DataType dataType) +{ + switch (dataType) + { + case DataType::Signed32: + case DataType::Float32: return 4U; + case DataType::QuantisedAsymm8: return 1U; + default: return 0U; + } +} + +template +constexpr bool StrEqual(const char* strA, const char (&strB)[N]) +{ + bool isEqual = true; + for (int i = 0; isEqual && (i < N); ++i) + { + isEqual = (strA[i] == strB[i]); + } + return isEqual; +} + +constexpr Compute ParseComputeDevice(const char* str) +{ + if (StrEqual(str, "CpuAcc")) + { + return armnn::Compute::CpuAcc; + } + else if (StrEqual(str, "CpuRef")) + { + return armnn::Compute::CpuRef; + } + else if (StrEqual(str, "GpuAcc")) + { + return armnn::Compute::GpuAcc; + } + else + { + return armnn::Compute::Undefined; + } +} + +constexpr const char* GetDataTypeName(DataType dataType) +{ + switch (dataType) + { + case DataType::Float32: return "Float32"; + case DataType::QuantisedAsymm8: return "Unsigned8"; + case DataType::Signed32: return "Signed32"; + default: return "Unknown"; + } +} + +template +constexpr DataType GetDataType(); + +template <> +constexpr DataType GetDataType() +{ + return DataType::Float32; +} + +template <> +constexpr DataType GetDataType() +{ + return DataType::QuantisedAsymm8; +} + +template <> +constexpr DataType GetDataType() +{ + return DataType::Signed32; +} + +template +constexpr bool IsQuantizedType() +{ + return std::is_integral::value; +} + + +template +struct ResolveTypeImpl; + +template<> +struct ResolveTypeImpl +{ + using Type = uint8_t; +}; + +template<> +struct ResolveTypeImpl +{ + using Type = float; +}; + +template +using ResolveType = typename ResolveTypeImpl
::Type; + + +inline std::ostream& operator<<(std::ostream& os, Status stat) +{ + os << GetStatusAsCString(stat); + return os; +} + +inline std::ostream& operator<<(std::ostream& os, Compute compute) +{ + os << GetComputeDeviceAsCString(compute); + return os; +} + +/// Quantize a floating point data type into an 8-bit data type +/// @param value The value to quantize +/// @param scale The scale (must be non-zero) +/// @param offset The offset +/// @return The quantized value calculated as round(value/scale)+offset +/// +template +inline QuantizedType Quantize(float value, float scale, int32_t offset) +{ + static_assert(IsQuantizedType(), "Not an integer type."); + constexpr QuantizedType max = std::numeric_limits::max(); + constexpr QuantizedType min = std::numeric_limits::lowest(); + BOOST_ASSERT(scale != 0.f); + int quantized = boost::numeric_cast(round(value / scale)) + offset; + QuantizedType quantizedBits = quantized < min ? min : quantized > max ? max : static_cast(quantized); + return quantizedBits; +} + +/// Dequantize an 8-bit data type into a floating point data type +/// @param value The value to dequantize +/// @param scale The scale (must be non-zero) +/// @param offset The offset +/// @return The dequantized value calculated as (value-offset)*scale +/// +template +inline float Dequantize(QuantizedType value, float scale, int32_t offset) +{ + static_assert(IsQuantizedType(), "Not an integer type."); + BOOST_ASSERT(scale != 0.f); + float dequantized = boost::numeric_cast(value - offset) * scale; + return dequantized; +} + +} //namespace armnn \ No newline at end of file diff --git a/include/armnn/Utils.hpp b/include/armnn/Utils.hpp new file mode 100644 index 0000000000..1a0c34baad --- /dev/null +++ b/include/armnn/Utils.hpp @@ -0,0 +1,27 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +namespace armnn +{ + +enum class LogSeverity +{ + Trace, + Debug, + Info, + Warning, + Error, + Fatal +}; + +/// Configures the logging behaviour of the ARMNN library. +/// printToStandardOutput: Set to true if log messages should be printed to the standard output. +/// printToDebugOutput: Set to true if log messages be printed to a platform-specific debug output +/// (where supported). +/// severity: All log messages that are at this severity level or higher will be printed, others will be ignored. +void ConfigureLogging(bool printToStandardOutput, bool printToDebugOutput, LogSeverity severity); + +} diff --git a/include/armnn/Version.hpp b/include/armnn/Version.hpp new file mode 100644 index 0000000000..6ce8256faa --- /dev/null +++ b/include/armnn/Version.hpp @@ -0,0 +1,12 @@ +// +// Copyright © 2017 Arm Ltd. All rights reserved. +// See LICENSE file in the project root for full license information. +// +#pragma once + +// YYYYMMPP +// where: +// YYYY = 4-digit year number +// MM = 2-digit month number +// PP = 2-digit patch number +#define ARMNN_VERSION "20180200" -- cgit v1.2.1