aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormathad01 <matthew.haddon@arm.com>2021-04-07 12:07:30 +0100
committermathad01 <matthew.haddon@arm.com>2021-04-12 15:31:28 +0100
commitb392e9845b7f40ab0c389f29f13f6ec84dd814d1 (patch)
treed71d260f7ff5ba7498ea653174bd166f27865ee5
parent35ad91c489312c23dddac5e6dffde840fbb85b79 (diff)
downloadarmnn-b392e9845b7f40ab0c389f29f13f6ec84dd814d1.tar.gz
IVGCVSW-5410 Add front-end support for CAST
IVGCVSW-5415 Add TfLiteParser support for CAST * Added front end support for CAST, including support in the Reference workload, Serialization, Deserializtion, Unit tests, and TfLiteParser. Signed-off-by: mathad01 <matthew.haddon@arm.com> Change-Id: Iaf670ca5912a21ed6bc84f7f83a68b42154846bb
-rw-r--r--Android.mk1
-rw-r--r--CMakeLists.txt4
-rw-r--r--docs/01_02_deserializer_serializer.dox2
-rw-r--r--include/armnn/BackendHelper.hpp4
-rw-r--r--include/armnn/ILayerSupport.hpp4
-rw-r--r--include/armnn/INetwork.hpp5
-rw-r--r--include/armnn/Types.hpp6
-rw-r--r--src/armnn/BackendHelper.cpp7
-rw-r--r--src/armnn/LayersFwd.hpp3
-rw-r--r--src/armnn/Network.cpp9
-rw-r--r--src/armnn/Network.hpp2
-rw-r--r--src/armnn/layers/CastLayer.cpp55
-rw-r--r--src/armnn/layers/CastLayer.hpp40
-rw-r--r--src/armnnDeserializer/Deserializer.cpp24
-rw-r--r--src/armnnDeserializer/Deserializer.hpp1
-rw-r--r--src/armnnDeserializer/test/DeserializeCast.cpp123
-rw-r--r--src/armnnSerializer/ArmnnSchema.fbs10
-rw-r--r--src/armnnSerializer/ArmnnSchema_generated.h87
-rw-r--r--src/armnnSerializer/Serializer.cpp16
-rw-r--r--src/armnnSerializer/Serializer.hpp3
-rw-r--r--src/armnnSerializer/test/SerializerTests.cpp27
-rw-r--r--src/armnnTfLiteParser/TfLiteParser.cpp25
-rw-r--r--src/armnnTfLiteParser/TfLiteParser.hpp1
-rw-r--r--src/armnnTfLiteParser/test/Cast.cpp88
-rw-r--r--src/backends/backendsCommon/LayerSupportBase.cpp7
-rw-r--r--src/backends/backendsCommon/LayerSupportBase.hpp4
-rw-r--r--src/backends/backendsCommon/WorkloadData.cpp27
-rw-r--r--src/backends/backendsCommon/WorkloadData.hpp5
-rw-r--r--src/backends/backendsCommon/WorkloadFactory.cpp16
-rw-r--r--src/backends/backendsCommon/WorkloadFactory.hpp3
-rw-r--r--src/backends/backendsCommon/common.mk1
-rw-r--r--src/backends/backendsCommon/test/CMakeLists.txt2
-rw-r--r--src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp2
-rw-r--r--src/backends/backendsCommon/test/LayerTests.hpp1
-rw-r--r--src/backends/backendsCommon/test/layerTests/CastTestImpl.cpp229
-rw-r--r--src/backends/backendsCommon/test/layerTests/CastTestImpl.hpp84
-rw-r--r--src/backends/reference/RefLayerSupport.cpp30
-rw-r--r--src/backends/reference/RefLayerSupport.hpp4
-rw-r--r--src/backends/reference/RefWorkloadFactory.cpp6
-rw-r--r--src/backends/reference/RefWorkloadFactory.hpp3
-rw-r--r--src/backends/reference/backend.mk1
-rw-r--r--src/backends/reference/test/RefLayerTests.cpp14
-rw-r--r--src/backends/reference/workloads/CMakeLists.txt2
-rw-r--r--src/backends/reference/workloads/RefCastWorkload.cpp40
-rw-r--r--src/backends/reference/workloads/RefCastWorkload.hpp24
-rw-r--r--src/backends/reference/workloads/RefWorkloads.hpp1
46 files changed, 1036 insertions, 17 deletions
diff --git a/Android.mk b/Android.mk
index 416c00238c..d9230e5585 100644
--- a/Android.mk
+++ b/Android.mk
@@ -153,6 +153,7 @@ LOCAL_SRC_FILES := \
src/armnn/layers/ArgMinMaxLayer.cpp \
src/armnn/layers/BatchNormalizationLayer.cpp \
src/armnn/layers/BatchToSpaceNdLayer.cpp \
+ src/armnn/layers/CastLayer.cpp \
src/armnn/layers/ComparisonLayer.cpp \
src/armnn/layers/ConcatLayer.cpp \
src/armnn/layers/ConstantLayer.cpp \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index edcf5cce63..6c3ef03a06 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -283,6 +283,8 @@ list(APPEND armnn_sources
src/armnn/layers/BatchNormalizationLayer.cpp
src/armnn/layers/BatchToSpaceNdLayer.hpp
src/armnn/layers/BatchToSpaceNdLayer.cpp
+ src/armnn/layers/CastLayer.hpp
+ src/armnn/layers/CastLayer.cpp
src/armnn/layers/ComparisonLayer.hpp
src/armnn/layers/ComparisonLayer.cpp
src/armnn/layers/ConcatLayer.hpp
@@ -809,6 +811,7 @@ if(BUILD_UNIT_TESTS)
src/armnnTfLiteParser/test/ArgMinMax.cpp
src/armnnTfLiteParser/test/AvgPool2D.cpp
src/armnnTfLiteParser/test/BatchToSpaceND.cpp
+ src/armnnTfLiteParser/test/Cast.cpp
src/armnnTfLiteParser/test/Concatenation.cpp
src/armnnTfLiteParser/test/Constant.cpp
src/armnnTfLiteParser/test/Conv2D.cpp
@@ -926,6 +929,7 @@ if(BUILD_UNIT_TESTS)
src/armnnDeserializer/test/DeserializeArgMinMax.cpp
src/armnnDeserializer/test/DeserializeBatchToSpaceNd.cpp
src/armnnDeserializer/test/DeserializeBatchNormalization.cpp
+ src/armnnDeserializer/test/DeserializeCast.cpp
src/armnnDeserializer/test/DeserializeComparison.cpp
src/armnnDeserializer/test/DeserializeConstant.cpp
src/armnnDeserializer/test/DeserializeConvolution2d.cpp
diff --git a/docs/01_02_deserializer_serializer.dox b/docs/01_02_deserializer_serializer.dox
index 6884b93dd1..1df3999d0a 100644
--- a/docs/01_02_deserializer_serializer.dox
+++ b/docs/01_02_deserializer_serializer.dox
@@ -24,6 +24,7 @@ The Arm NN SDK Serializer currently supports the following layers:
- ArgMinMax
- BatchToSpaceNd
- BatchNormalization
+- Cast
- Comparison
- Concat
- Constant
@@ -109,6 +110,7 @@ The Arm NN SDK Deserialize parser currently supports the following layers:
- ArgMinMax
- BatchToSpaceNd
- BatchNormalization
+- Cast
- Concat
- Comparison
- Constant
diff --git a/include/armnn/BackendHelper.hpp b/include/armnn/BackendHelper.hpp
index 41bb5f9c3a..2958980669 100644
--- a/include/armnn/BackendHelper.hpp
+++ b/include/armnn/BackendHelper.hpp
@@ -61,6 +61,10 @@ public:
const BatchToSpaceNdDescriptor& descriptor,
Optional<std::string&> reasonIfUnsupported = EmptyOptional());
+ bool IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported = EmptyOptional());
+
bool IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/include/armnn/ILayerSupport.hpp b/include/armnn/ILayerSupport.hpp
index 602e4e5b57..52b6df7117 100644
--- a/include/armnn/ILayerSupport.hpp
+++ b/include/armnn/ILayerSupport.hpp
@@ -60,6 +60,10 @@ public:
const BatchToSpaceNdDescriptor& descriptor,
Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const = 0;
+ virtual bool IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const = 0;
+
virtual bool IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp
index 5d2b4edb00..2cdbe1a939 100644
--- a/include/armnn/INetwork.hpp
+++ b/include/armnn/INetwork.hpp
@@ -198,6 +198,11 @@ public:
IConnectableLayer* AddArgMinMaxLayer(const ArgMinMaxDescriptor& desc,
const char* name = nullptr);
+ /// Adds a cast layer to the network.
+ /// @param name - Optional name for the layer.
+ /// @return - Interface for configuring the layer.
+ IConnectableLayer* AddCastLayer(const char* name = nullptr);
+
/// Add a Comparison layer to the network.
/// @param name - Optional name for the layer.
/// @param desc - Descriptor for the comparison operation.
diff --git a/include/armnn/Types.hpp b/include/armnn/Types.hpp
index 07d38a332d..2fd40b84dd 100644
--- a/include/armnn/Types.hpp
+++ b/include/armnn/Types.hpp
@@ -425,8 +425,8 @@ struct ProfilingStaticGuid : public ProfilingGuid
X(Switch) \
X(Transpose) \
X(TransposeConvolution2d) \
- X(Unmap)
-
+ X(Unmap) \
+ X(Cast)
/// When adding a new layer, adapt also the LastLayer enum value in the
/// enum class LayerType below
enum class LayerType
@@ -435,7 +435,7 @@ enum class LayerType
LIST_OF_LAYER_TYPE
#undef X
FirstLayer = Activation,
- LastLayer = Unmap
+ LastLayer = Cast
};
const char* GetLayerTypeAsCString(LayerType type);
diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp
index 1c926f4d30..31dfaa53a3 100644
--- a/src/armnn/BackendHelper.cpp
+++ b/src/armnn/BackendHelper.cpp
@@ -113,6 +113,13 @@ bool LayerSupportHandle::IsBatchToSpaceNdSupported(const TensorInfo& input,
reasonIfUnsupported.value());
}
+bool LayerSupportHandle::IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported)
+{
+ return m_LayerSupport->IsCastSupported(input, output, reasonIfUnsupported.value());
+}
+
bool LayerSupportHandle::IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/src/armnn/LayersFwd.hpp b/src/armnn/LayersFwd.hpp
index 6782fb5eb7..19cd9bdf6c 100644
--- a/src/armnn/LayersFwd.hpp
+++ b/src/armnn/LayersFwd.hpp
@@ -11,6 +11,7 @@
#include "layers/ArgMinMaxLayer.hpp"
#include "layers/BatchNormalizationLayer.hpp"
#include "layers/BatchToSpaceNdLayer.hpp"
+#include "layers/CastLayer.hpp"
#include "layers/ComparisonLayer.hpp"
#include "layers/ConcatLayer.hpp"
#include "layers/ConstantLayer.hpp"
@@ -166,5 +167,5 @@ DECLARE_LAYER(Switch)
DECLARE_LAYER(Transpose)
DECLARE_LAYER(TransposeConvolution2d)
DECLARE_LAYER(Unmap)
-
+DECLARE_LAYER(Cast)
}
diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp
index b9a0e47ec5..860048fecd 100644
--- a/src/armnn/Network.cpp
+++ b/src/armnn/Network.cpp
@@ -59,6 +59,10 @@ IConnectableLayer* INetwork::AddArgMinMaxLayer(const ArgMinMaxDescriptor& desc,
return pNetworkImpl->AddArgMinMaxLayer(desc, name);
}
+IConnectableLayer* INetwork::AddCastLayer(const char* name)
+{
+ return pNetworkImpl->AddCastLayer(name);
+}
IConnectableLayer* INetwork::AddComparisonLayer(const ComparisonDescriptor& comparisonDescriptor,
const char* name)
@@ -1705,6 +1709,11 @@ IConnectableLayer* NetworkImpl::AddBatchToSpaceNdLayer(const BatchToSpaceNdDescr
return m_Graph->AddLayer<BatchToSpaceNdLayer>(batchToSpaceNdDescriptor, name);
}
+IConnectableLayer* NetworkImpl::AddCastLayer(const char* name)
+{
+ return m_Graph->AddLayer<CastLayer>(name);
+}
+
IConnectableLayer* NetworkImpl::AddComparisonLayer(const ComparisonDescriptor& comparisonDescriptor,
const char* name)
{
diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp
index 30941ca9e4..ad9b51cf35 100644
--- a/src/armnn/Network.hpp
+++ b/src/armnn/Network.hpp
@@ -46,6 +46,8 @@ public:
IConnectableLayer* AddBatchToSpaceNdLayer(const BatchToSpaceNdDescriptor& batchToSpaceNdDescriptor,
const char* name = nullptr);
+ IConnectableLayer* AddCastLayer(const char* name = nullptr);
+
IConnectableLayer* AddComparisonLayer(const ComparisonDescriptor& comparisonDescriptor,
const char* name = nullptr);
diff --git a/src/armnn/layers/CastLayer.cpp b/src/armnn/layers/CastLayer.cpp
new file mode 100644
index 0000000000..16dd9a3744
--- /dev/null
+++ b/src/armnn/layers/CastLayer.cpp
@@ -0,0 +1,55 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+#include "CastLayer.hpp"
+
+#include "LayerCloneBase.hpp"
+#include <armnn/TypesUtils.hpp>
+
+#include <backendsCommon/WorkloadData.hpp>
+#include <backendsCommon/WorkloadFactory.hpp>
+
+namespace armnn
+{
+
+CastLayer::CastLayer(const char* name)
+ : Layer(1, 1, LayerType::Cast, name)
+{
+}
+
+std::unique_ptr<IWorkload> CastLayer::CreateWorkload(const IWorkloadFactory& factory) const
+{
+ CastQueueDescriptor descriptor;
+ SetAdditionalInfo(descriptor);
+
+ return factory.CreateCast(descriptor, PrepInfoAndDesc(descriptor));
+}
+
+CastLayer* CastLayer::Clone(Graph& graph) const
+{
+ return CloneBase<CastLayer>(graph, GetName());
+}
+
+void CastLayer::ValidateTensorShapesFromInputs()
+{
+ VerifyLayerConnections(1, CHECK_LOCATION());
+
+ const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
+
+ VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
+
+ auto inferredShapes = InferOutputShapes({ GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape() });
+
+ ARMNN_ASSERT(inferredShapes.size() == 1);
+
+ ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "CastLayer");
+}
+
+void CastLayer::Accept(ILayerVisitor& visitor) const
+{
+ IgnoreUnused(visitor);
+ throw armnn::Exception("CastLayer VisitCastLayer is not implemented");
+}
+
+} // namespace armnn
diff --git a/src/armnn/layers/CastLayer.hpp b/src/armnn/layers/CastLayer.hpp
new file mode 100644
index 0000000000..8a9ea43934
--- /dev/null
+++ b/src/armnn/layers/CastLayer.hpp
@@ -0,0 +1,40 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "Layer.hpp"
+
+namespace armnn
+{
+
+/// This layer represents a cast operation
+class CastLayer : public Layer
+{
+public:
+ /// Makes a workload for the Cast type.
+ /// @param [in] factory The workload factory which will create the workload.
+ /// @return A pointer to the created workload, or nullptr if not created.
+ virtual std::unique_ptr <IWorkload> CreateWorkload(const IWorkloadFactory &factory) const override;
+
+ /// Creates a dynamically-allocated copy of this layer.
+ /// @param [in] graph The graph into which this layer is being cloned.
+ CastLayer* Clone(Graph& graph) const override;
+
+ /// Check if the input tensor shape(s)
+ /// will lead to a valid configuration of @ref ConvertFp16ToFp32Layer.
+ /// @param [in] shapeInferenceMethod Indicates if output shape shall be overwritten or just validated.
+ void ValidateTensorShapesFromInputs() override;
+
+ void Accept(ILayerVisitor& visitor) const override;
+
+protected:
+ /// Constructor to create a CastLayer.
+ CastLayer(const char *name);
+
+ /// Default destructor
+ ~CastLayer() = default;
+};
+} // namespace armnn \ No newline at end of file
diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp
index 89a42b60aa..976986eec3 100644
--- a/src/armnnDeserializer/Deserializer.cpp
+++ b/src/armnnDeserializer/Deserializer.cpp
@@ -216,6 +216,7 @@ m_ParserFunctions(Layer_MAX+1, &IDeserializer::DeserializerImpl::ParseUnsupporte
m_ParserFunctions[Layer_BatchToSpaceNdLayer] = &DeserializerImpl::ParseBatchToSpaceNd;
m_ParserFunctions[Layer_BatchNormalizationLayer] = &DeserializerImpl::ParseBatchNormalization;
m_ParserFunctions[Layer_ComparisonLayer] = &DeserializerImpl::ParseComparison;
+ m_ParserFunctions[Layer_CastLayer] = &DeserializerImpl::ParseCast;
m_ParserFunctions[Layer_ConcatLayer] = &DeserializerImpl::ParseConcat;
m_ParserFunctions[Layer_ConstantLayer] = &DeserializerImpl::ParseConstant;
m_ParserFunctions[Layer_Convolution2dLayer] = &DeserializerImpl::ParseConvolution2d;
@@ -288,6 +289,8 @@ LayerBaseRawPtr IDeserializer::DeserializerImpl::GetBaseLayer(const GraphPtr& gr
return graphPtr->layers()->Get(layerIndex)->layer_as_BatchToSpaceNdLayer()->base();
case Layer::Layer_BatchNormalizationLayer:
return graphPtr->layers()->Get(layerIndex)->layer_as_BatchNormalizationLayer()->base();
+ case Layer::Layer_CastLayer:
+ return graphPtr->layers()->Get(layerIndex)->layer_as_CastLayer()->base();
case Layer::Layer_ComparisonLayer:
return graphPtr->layers()->Get(layerIndex)->layer_as_ComparisonLayer()->base();
case Layer::Layer_ConcatLayer:
@@ -1275,6 +1278,27 @@ void IDeserializer::DeserializerImpl::ParseBatchNormalization(GraphPtr graph, un
RegisterOutputSlots(graph, layerIndex, layer);
}
+void IDeserializer::DeserializerImpl::ParseCast(GraphPtr graph, unsigned int layerIndex)
+{
+ CHECK_LAYERS(graph, 0, layerIndex);
+ TensorRawPtrVector inputs = GetInputs(graph, layerIndex);
+ CHECK_LOCATION();
+ CHECK_VALID_SIZE(inputs.size(), 1);
+
+ TensorRawPtrVector outputs = GetOutputs(graph, layerIndex);
+ CHECK_VALID_SIZE(outputs.size(), 1);
+
+ auto layerName = GetLayerName(graph, layerIndex);
+
+ IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
+
+ armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
+ layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ RegisterInputSlots(graph, layerIndex, layer);
+ RegisterOutputSlots(graph, layerIndex, layer);
+}
+
void IDeserializer::DeserializerImpl::ParseConstant(GraphPtr graph, unsigned int layerIndex)
{
CHECK_LAYERS(graph, 0, layerIndex);
diff --git a/src/armnnDeserializer/Deserializer.hpp b/src/armnnDeserializer/Deserializer.hpp
index f4f64240a0..3465011e65 100644
--- a/src/armnnDeserializer/Deserializer.hpp
+++ b/src/armnnDeserializer/Deserializer.hpp
@@ -84,6 +84,7 @@ private:
void ParseArgMinMax(GraphPtr graph, unsigned int layerIndex);
void ParseBatchToSpaceNd(GraphPtr graph, unsigned int layerIndex);
void ParseBatchNormalization(GraphPtr graph, unsigned int layerIndex);
+ void ParseCast(GraphPtr graph, unsigned int layerIndex);
void ParseComparison(GraphPtr graph, unsigned int layerIndex);
void ParseConcat(GraphPtr graph, unsigned int layerIndex);
void ParseConstant(GraphPtr graph, unsigned int layerIndex);
diff --git a/src/armnnDeserializer/test/DeserializeCast.cpp b/src/armnnDeserializer/test/DeserializeCast.cpp
new file mode 100644
index 0000000000..c8e3e10871
--- /dev/null
+++ b/src/armnnDeserializer/test/DeserializeCast.cpp
@@ -0,0 +1,123 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "ParserFlatbuffersSerializeFixture.hpp"
+#include <armnnDeserializer/IDeserializer.hpp>
+
+#include <QuantizeHelper.hpp>
+#include <ResolveType.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <string>
+
+BOOST_AUTO_TEST_SUITE(Deserializer)
+
+
+struct CastFixture : public ParserFlatbuffersSerializeFixture
+{
+ explicit CastFixture(const std::string& inputShape,
+ const std::string& outputShape,
+ const std::string& inputDataType,
+ const std::string& outputDataType)
+ {
+ m_JsonString = R"(
+ {
+ inputIds: [0],
+ outputIds: [2],
+ layers: [
+ {
+ layer_type: "InputLayer",
+ layer: {
+ base: {
+ layerBindingId: 0,
+ base: {
+ index: 0,
+ layerName: "inputTensor",
+ layerType: "Input",
+ inputSlots: [{
+ index: 0,
+ connection: { sourceLayerIndex:0, outputSlotIndex:0 },
+ }],
+ outputSlots: [{
+ index: 0,
+ tensorInfo: {
+ dimensions: )" + inputShape + R"(,
+ dataType: )" + inputDataType + R"(
+ }
+ }]
+ }
+ }
+ }
+ },
+ {
+ layer_type: "CastLayer",
+ layer: {
+ base: {
+ index:1,
+ layerName: "CastLayer",
+ layerType: "Cast",
+ inputSlots: [{
+ index: 0,
+ connection: { sourceLayerIndex:0, outputSlotIndex:0 },
+ }],
+ outputSlots: [{
+ index: 0,
+ tensorInfo: {
+ dimensions: )" + outputShape + R"(,
+ dataType: )" + outputDataType + R"(
+ },
+ }],
+ },
+ },
+ },
+ {
+ layer_type: "OutputLayer",
+ layer: {
+ base:{
+ layerBindingId: 2,
+ base: {
+ index: 2,
+ layerName: "outputTensor",
+ layerType: "Output",
+ inputSlots: [{
+ index: 0,
+ connection: { sourceLayerIndex:1, outputSlotIndex:0 },
+ }],
+ outputSlots: [{
+ index: 0,
+ tensorInfo: {
+ dimensions: )" + outputShape + R"(,
+ dataType: )" + outputDataType + R"(
+ },
+ }],
+ }
+ }
+ },
+ }
+ ]
+ }
+ )";
+ Setup();
+ }
+};
+
+struct SimpleCastFixture : CastFixture
+{
+ SimpleCastFixture() : CastFixture("[ 1, 6 ]",
+ "[ 1, 6 ]",
+ "Signed32",
+ "Float32") {}
+};
+
+BOOST_FIXTURE_TEST_CASE(SimpleCast, SimpleCastFixture)
+{
+RunTest<2, armnn::DataType::Signed32 , armnn::DataType::Float32>(
+0,
+{{"inputTensor", { 0, -1, 5, -100, 200, -255 }}},
+{{"outputTensor", { 0.0f, -1.0f, 5.0f, -100.0f, 200.0f, -255.0f }}});
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index 438ea839f8..a409715600 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -170,7 +170,8 @@ enum LayerType : uint {
Fill = 57,
Rank = 58,
LogicalBinary = 59,
- Reduce = 60
+ Reduce = 60,
+ Cast = 61
}
// Base layer table to be used as part of other layers
@@ -219,6 +220,10 @@ table ArgMinMaxDescriptor{
axis:int;
}
+table CastLayer {
+ base:LayerBase;
+}
+
enum ComparisonOperation : byte {
Equal = 0,
Greater = 1,
@@ -964,7 +969,8 @@ union Layer {
FillLayer,
RankLayer,
LogicalBinaryLayer,
- ReduceLayer
+ ReduceLayer,
+ CastLayer
}
table AnyLayer {
diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h
index 2cd88e2718..dfa496647f 100644
--- a/src/armnnSerializer/ArmnnSchema_generated.h
+++ b/src/armnnSerializer/ArmnnSchema_generated.h
@@ -61,6 +61,9 @@ struct ArgMinMaxLayerBuilder;
struct ArgMinMaxDescriptor;
struct ArgMinMaxDescriptorBuilder;
+struct CastLayer;
+struct CastLayerBuilder;
+
struct ComparisonDescriptor;
struct ComparisonDescriptorBuilder;
@@ -731,11 +734,12 @@ enum LayerType {
LayerType_Rank = 58,
LayerType_LogicalBinary = 59,
LayerType_Reduce = 60,
+ LayerType_Cast = 61,
LayerType_MIN = LayerType_Addition,
- LayerType_MAX = LayerType_Reduce
+ LayerType_MAX = LayerType_Cast
};
-inline const LayerType (&EnumValuesLayerType())[61] {
+inline const LayerType (&EnumValuesLayerType())[62] {
static const LayerType values[] = {
LayerType_Addition,
LayerType_Input,
@@ -797,13 +801,14 @@ inline const LayerType (&EnumValuesLayerType())[61] {
LayerType_Fill,
LayerType_Rank,
LayerType_LogicalBinary,
- LayerType_Reduce
+ LayerType_Reduce,
+ LayerType_Cast
};
return values;
}
inline const char * const *EnumNamesLayerType() {
- static const char * const names[62] = {
+ static const char * const names[63] = {
"Addition",
"Input",
"Multiplication",
@@ -865,13 +870,14 @@ inline const char * const *EnumNamesLayerType() {
"Rank",
"LogicalBinary",
"Reduce",
+ "Cast",
nullptr
};
return names;
}
inline const char *EnumNameLayerType(LayerType e) {
- if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Reduce)) return "";
+ if (flatbuffers::IsOutRange(e, LayerType_Addition, LayerType_Cast)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesLayerType()[index];
}
@@ -1206,11 +1212,12 @@ enum Layer {
Layer_RankLayer = 59,
Layer_LogicalBinaryLayer = 60,
Layer_ReduceLayer = 61,
+ Layer_CastLayer = 62,
Layer_MIN = Layer_NONE,
- Layer_MAX = Layer_ReduceLayer
+ Layer_MAX = Layer_CastLayer
};
-inline const Layer (&EnumValuesLayer())[62] {
+inline const Layer (&EnumValuesLayer())[63] {
static const Layer values[] = {
Layer_NONE,
Layer_ActivationLayer,
@@ -1273,13 +1280,14 @@ inline const Layer (&EnumValuesLayer())[62] {
Layer_FillLayer,
Layer_RankLayer,
Layer_LogicalBinaryLayer,
- Layer_ReduceLayer
+ Layer_ReduceLayer,
+ Layer_CastLayer
};
return values;
}
inline const char * const *EnumNamesLayer() {
- static const char * const names[63] = {
+ static const char * const names[64] = {
"NONE",
"ActivationLayer",
"AdditionLayer",
@@ -1342,13 +1350,14 @@ inline const char * const *EnumNamesLayer() {
"RankLayer",
"LogicalBinaryLayer",
"ReduceLayer",
+ "CastLayer",
nullptr
};
return names;
}
inline const char *EnumNameLayer(Layer e) {
- if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_ReduceLayer)) return "";
+ if (flatbuffers::IsOutRange(e, Layer_NONE, Layer_CastLayer)) return "";
const size_t index = static_cast<size_t>(e);
return EnumNamesLayer()[index];
}
@@ -1601,6 +1610,10 @@ template<> struct LayerTraits<armnnSerializer::ReduceLayer> {
static const Layer enum_value = Layer_ReduceLayer;
};
+template<> struct LayerTraits<armnnSerializer::CastLayer> {
+ static const Layer enum_value = Layer_CastLayer;
+};
+
bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer type);
bool VerifyLayerVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
@@ -2640,6 +2653,49 @@ inline flatbuffers::Offset<ArgMinMaxDescriptor> CreateArgMinMaxDescriptor(
return builder_.Finish();
}
+struct CastLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef CastLayerBuilder Builder;
+ enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
+ VT_BASE = 4
+ };
+ const armnnSerializer::LayerBase *base() const {
+ return GetPointer<const armnnSerializer::LayerBase *>(VT_BASE);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyOffset(verifier, VT_BASE) &&
+ verifier.VerifyTable(base()) &&
+ verifier.EndTable();
+ }
+};
+
+struct CastLayerBuilder {
+ typedef CastLayer Table;
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_base(flatbuffers::Offset<armnnSerializer::LayerBase> base) {
+ fbb_.AddOffset(CastLayer::VT_BASE, base);
+ }
+ explicit CastLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ CastLayerBuilder &operator=(const CastLayerBuilder &);
+ flatbuffers::Offset<CastLayer> Finish() {
+ const auto end = fbb_.EndTable(start_);
+ auto o = flatbuffers::Offset<CastLayer>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<CastLayer> CreateCastLayer(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ flatbuffers::Offset<armnnSerializer::LayerBase> base = 0) {
+ CastLayerBuilder builder_(_fbb);
+ builder_.add_base(base);
+ return builder_.Finish();
+}
+
struct ComparisonDescriptor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef ComparisonDescriptorBuilder Builder;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
@@ -9502,6 +9558,9 @@ struct AnyLayer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const armnnSerializer::ReduceLayer *layer_as_ReduceLayer() const {
return layer_type() == armnnSerializer::Layer_ReduceLayer ? static_cast<const armnnSerializer::ReduceLayer *>(layer()) : nullptr;
}
+ const armnnSerializer::CastLayer *layer_as_CastLayer() const {
+ return layer_type() == armnnSerializer::Layer_CastLayer ? static_cast<const armnnSerializer::CastLayer *>(layer()) : nullptr;
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint8_t>(verifier, VT_LAYER_TYPE) &&
@@ -9755,6 +9814,10 @@ template<> inline const armnnSerializer::ReduceLayer *AnyLayer::layer_as<armnnSe
return layer_as_ReduceLayer();
}
+template<> inline const armnnSerializer::CastLayer *AnyLayer::layer_as<armnnSerializer::CastLayer>() const {
+ return layer_as_CastLayer();
+}
+
struct AnyLayerBuilder {
typedef AnyLayer Table;
flatbuffers::FlatBufferBuilder &fbb_;
@@ -10209,6 +10272,10 @@ inline bool VerifyLayer(flatbuffers::Verifier &verifier, const void *obj, Layer
auto ptr = reinterpret_cast<const armnnSerializer::ReduceLayer *>(obj);
return verifier.VerifyTable(ptr);
}
+ case Layer_CastLayer: {
+ auto ptr = reinterpret_cast<const armnnSerializer::CastLayer *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
default: return true;
}
}
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 15ae78cb65..b742cd87d8 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -14,7 +14,6 @@
#include <fmt/format.h>
#include <iostream>
-
using namespace armnn;
namespace fb = flatbuffers;
namespace serializer = armnnSerializer;
@@ -293,6 +292,16 @@ void SerializerStrategy::SerializeBatchNormalizationLayer(
CreateAnyLayer(fbBatchNormalizationLayer.o, serializer::Layer::Layer_BatchNormalizationLayer);
}
+void SerializerStrategy::SerializeCastLayer(const armnn::IConnectableLayer* layer,
+ const char* name)
+{
+ IgnoreUnused(name);
+
+ auto fbBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Cast);
+ auto fbCastLayer = serializer::CreateCastLayer(m_flatBufferBuilder, fbBaseLayer);
+ CreateAnyLayer(fbCastLayer.o, serializer::Layer::Layer_CastLayer);
+}
+
void SerializerStrategy::SerializeComparisonLayer(const armnn::IConnectableLayer* layer,
const armnn::ComparisonDescriptor& descriptor,
const char* name)
@@ -1868,6 +1877,11 @@ void SerializerStrategy::ExecuteStrategy(const armnn::IConnectableLayer* layer,
name);
break;
}
+ case armnn::LayerType::Cast :
+ {
+ SerializeCastLayer(layer, name);
+ break;
+ }
case armnn::LayerType::Comparison :
{
const armnn::ComparisonDescriptor& layerDescriptor =
diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp
index 7226006cea..022cf64592 100644
--- a/src/armnnSerializer/Serializer.hpp
+++ b/src/armnnSerializer/Serializer.hpp
@@ -126,6 +126,9 @@ private:
const std::vector<armnn::ConstTensor>& constants,
const char* name = nullptr);
+ void SerializeCastLayer(const armnn::IConnectableLayer* layer,
+ const char* name = nullptr);
+
void SerializeComparisonLayer(const armnn::IConnectableLayer* layer,
const armnn::ComparisonDescriptor& descriptor,
const char* name = nullptr);
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index 9d44354cdd..3d6dd58923 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -200,6 +200,33 @@ BOOST_AUTO_TEST_CASE(SerializeBatchToSpaceNd)
deserializedNetwork->ExecuteStrategy(verifier);
}
+BOOST_AUTO_TEST_CASE(SerializeCast)
+{
+ const std::string layerName("cast");
+
+ const armnn::TensorShape shape{1, 5, 2, 3};
+
+ const armnn::TensorInfo inputInfo = armnn::TensorInfo(shape, armnn::DataType::Signed32);
+ const armnn::TensorInfo outputInfo = armnn::TensorInfo(shape, armnn::DataType::Float32);
+
+ armnn::INetworkPtr network = armnn::INetwork::Create();
+ armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0);
+ armnn::IConnectableLayer* castLayer = network->AddCastLayer(layerName.c_str());
+ armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0);
+
+ inputLayer->GetOutputSlot(0).Connect(castLayer->GetInputSlot(0));
+ castLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+ inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+ castLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+ armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+ BOOST_CHECK(deserializedNetwork);
+
+ LayerVerifierBase verifier(layerName, {inputInfo}, {outputInfo});
+ deserializedNetwork->ExecuteStrategy(verifier);
+}
+
BOOST_AUTO_TEST_CASE(SerializeComparison)
{
const std::string layerName("comparison");
diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp
index cb3426ea5b..5f8b08bf85 100644
--- a/src/armnnTfLiteParser/TfLiteParser.cpp
+++ b/src/armnnTfLiteParser/TfLiteParser.cpp
@@ -608,6 +608,7 @@ TfLiteParserImpl::TfLiteParserImpl(const Optional<ITfLiteParser::TfLiteParserOpt
m_ParserFunctions[tflite::BuiltinOperator_ARG_MAX] = &TfLiteParserImpl::ParseArgMax;
m_ParserFunctions[tflite::BuiltinOperator_AVERAGE_POOL_2D] = &TfLiteParserImpl::ParseAveragePool2D;
m_ParserFunctions[tflite::BuiltinOperator_BATCH_TO_SPACE_ND] = &TfLiteParserImpl::ParseBatchToSpaceND;
+ m_ParserFunctions[tflite::BuiltinOperator_CAST] = &TfLiteParserImpl::ParseCast;
m_ParserFunctions[tflite::BuiltinOperator_CONCATENATION] = &TfLiteParserImpl::ParseConcatenation;
m_ParserFunctions[tflite::BuiltinOperator_CONV_2D] = &TfLiteParserImpl::ParseConv2D;
m_ParserFunctions[tflite::BuiltinOperator_CUSTOM] = &TfLiteParserImpl::ParseCustomOperator;
@@ -876,6 +877,30 @@ void TfLiteParserImpl::ParseUnsupportedOperator(size_t subgraphIndex, size_t ope
RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIds);
}
+void TfLiteParserImpl::ParseCast(size_t subgraphIndex, size_t operatorIndex)
+{
+ CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
+
+ auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
+ CHECK_VALID_SIZE(inputs.size(), 1);
+ auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
+ CHECK_VALID_SIZE(outputs.size(), 1);
+
+ auto layerName = fmt::format("Cast:{}:{}", subgraphIndex, operatorIndex);
+
+ IConnectableLayer* layer = m_Network->AddCastLayer(layerName.c_str());
+ ARMNN_ASSERT(layer != nullptr);
+
+ TensorInfo outputTensorInfo = ToTensorInfo(outputs[0], true);
+ layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
+
+ auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
+ RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
+
+ auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
+ RegisterOutputSlots(subgraphIndex, operatorIndex, layer, outputTensorIndexes);
+}
+
void TfLiteParserImpl::ParseConv2D(size_t subgraphIndex, size_t operatorIndex)
{
CHECK_MODEL(m_Model, subgraphIndex, operatorIndex);
diff --git a/src/armnnTfLiteParser/TfLiteParser.hpp b/src/armnnTfLiteParser/TfLiteParser.hpp
index 90517f5aad..af844d2ef3 100644
--- a/src/armnnTfLiteParser/TfLiteParser.hpp
+++ b/src/armnnTfLiteParser/TfLiteParser.hpp
@@ -104,6 +104,7 @@ private:
void ParseArgMax(size_t subgraphIndex, size_t operatorIndex);
void ParseAveragePool2D(size_t subgraphIndex, size_t operatorIndex);
void ParseBatchToSpaceND(size_t subgraphIndex, size_t operatorIndex);
+ void ParseCast(size_t subgraphIndex, size_t operatorIndex);
void ParseConcatenation(size_t subgraphIndex, size_t operatorIndex);
void ParseConv2D(size_t subgraphIndex, size_t operatorIndex);
void ParseDepthToSpace(size_t subgraphIndex, size_t operatorIndex);
diff --git a/src/armnnTfLiteParser/test/Cast.cpp b/src/armnnTfLiteParser/test/Cast.cpp
new file mode 100644
index 0000000000..e0f9c63e72
--- /dev/null
+++ b/src/armnnTfLiteParser/test/Cast.cpp
@@ -0,0 +1,88 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include <boost/test/unit_test.hpp>
+#include "ParserFlatbuffersFixture.hpp"
+#include "../TfLiteParser.hpp"
+
+#include <string>
+#include <iostream>
+
+BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
+
+struct CastFixture : public ParserFlatbuffersFixture
+{
+ explicit CastFixture(const std::string& inputShape,
+ const std::string& outputShape,
+ const std::string& inputDataType,
+ const std::string& outputDataType)
+ {
+ m_JsonString = R"(
+ {
+ "version": 3,
+ "operator_codes": [ { "builtin_code": "CAST" } ],
+ "subgraphs": [ {
+ "tensors": [
+ {
+ "shape": )" + inputShape + R"(,
+ "type": )" + inputDataType + R"(,
+ "buffer": 0,
+ "name": "inputTensor",
+ "quantization": {
+ "min": [ 0.0 ],
+ "max": [ 255.0 ],
+ "scale": [ 1.0 ],
+ "zero_point": [ 0 ],
+ }
+ },
+ {
+ "shape": )" + outputShape + R"(,
+ "type": )" + outputDataType + R"(,
+ "buffer": 1,
+ "name": "outputTensor",
+ "quantization": {
+ "min": [ 0.0 ],
+ "max": [ 255.0 ],
+ "scale": [ 1.0 ],
+ "zero_point": [ 0 ],
+ }
+ }
+ ],
+ "inputs": [ 0 ],
+ "outputs": [ 1 ],
+ "operators": [
+ {
+ "opcode_index": 0,
+ "inputs": [ 0 ],
+ "outputs": [ 1 ],
+ "custom_options_format": "FLEXBUFFERS"
+ }
+ ],
+ } ],
+ "buffers" : [ {}, {} ]
+ }
+ )";
+ SetupSingleInputSingleOutput("inputTensor", "outputTensor");
+ }
+};
+
+struct SimpleCastFixture : CastFixture
+{
+ SimpleCastFixture() : CastFixture("[ 1, 6 ]",
+ "[ 1, 6 ]",
+ "INT32",
+ "FLOAT32") {}
+};
+
+BOOST_FIXTURE_TEST_CASE(SimpleCast, SimpleCastFixture)
+{
+RunTest<2, armnn::DataType::Signed32 , armnn::DataType::Float32>(
+0,
+{{"inputTensor", { 0, -1, 5, -100, 200, -255 }}},
+{{"outputTensor", { 0.0f, -1.0f, 5.0f, -100.0f, 200.0f, -255.0f }}});
+}
+
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/backends/backendsCommon/LayerSupportBase.cpp b/src/backends/backendsCommon/LayerSupportBase.cpp
index 77067d9c6c..2e171f98ae 100644
--- a/src/backends/backendsCommon/LayerSupportBase.cpp
+++ b/src/backends/backendsCommon/LayerSupportBase.cpp
@@ -88,6 +88,13 @@ bool LayerSupportBase::IsBatchToSpaceNdSupported(const TensorInfo&, // input
return DefaultLayerSupport(__func__, __FILE__, __LINE__, reasonIfUnsupported);
}
+bool LayerSupportBase::IsCastSupported(const TensorInfo&, //input
+ const TensorInfo&, //output
+ Optional<std::string &> reasonIfUnsupported) const
+{
+ return DefaultLayerSupport(__func__, __FILE__, __LINE__, reasonIfUnsupported);
+}
+
bool LayerSupportBase::IsComparisonSupported(const TensorInfo&, // input0
const TensorInfo&, // input1
const TensorInfo&, // output
diff --git a/src/backends/backendsCommon/LayerSupportBase.hpp b/src/backends/backendsCommon/LayerSupportBase.hpp
index e04d657716..a6f1b34b61 100644
--- a/src/backends/backendsCommon/LayerSupportBase.hpp
+++ b/src/backends/backendsCommon/LayerSupportBase.hpp
@@ -47,6 +47,10 @@ public:
const BatchToSpaceNdDescriptor& descriptor,
Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
+ bool IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
+
bool IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 2c5303c019..100d23ee39 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -706,6 +706,33 @@ void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
}
}
+void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
+{
+ const std::string descriptorName{"CastQueueDescriptor"};
+
+ ValidateNumInputs(workloadInfo, descriptorName, 1);
+ ValidateNumOutputs(workloadInfo, descriptorName, 1);
+
+ const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0];
+ const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0];
+
+ std::vector<DataType> supportedTypes =
+ {
+ DataType::BFloat16,
+ DataType::Float16,
+ DataType::Float32,
+ DataType::QAsymmS8,
+ DataType::QAsymmU8,
+ DataType::QSymmS8,
+ DataType::QSymmS16,
+ DataType::Signed32,
+ DataType::Signed64
+ };
+
+ ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName);
+ ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output");
+}
+
void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const
{
const std::string descriptorName{"SoftmaxQueueDescriptor"};
diff --git a/src/backends/backendsCommon/WorkloadData.hpp b/src/backends/backendsCommon/WorkloadData.hpp
index 8a2dd1fe78..abaa4f5185 100644
--- a/src/backends/backendsCommon/WorkloadData.hpp
+++ b/src/backends/backendsCommon/WorkloadData.hpp
@@ -155,6 +155,11 @@ struct ArgMinMaxQueueDescriptor : QueueDescriptorWithParameters<ArgMinMaxDescrip
void Validate(const WorkloadInfo& workloadInfo) const;
};
+struct CastQueueDescriptor : QueueDescriptor
+{
+ void Validate(const WorkloadInfo& workloadInfo) const;
+};
+
// Fill layer workload data.
struct FillQueueDescriptor : QueueDescriptorWithParameters<FillDescriptor>
{
diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp
index 20d7134c3a..9d7d5bd26d 100644
--- a/src/backends/backendsCommon/WorkloadFactory.cpp
+++ b/src/backends/backendsCommon/WorkloadFactory.cpp
@@ -138,6 +138,16 @@ bool IWorkloadFactory::IsLayerConfigurationSupported(const BackendId& backendId,
reason);
break;
}
+ case LayerType::Cast:
+ {
+ const TensorInfo& input = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
+ const TensorInfo& output = layer.GetOutputSlot(0).GetTensorInfo();
+
+ result = layerSupportObject.IsCastSupported(OverrideDataType(input, dataType),
+ OverrideDataType(output, dataType),
+ reason);
+ break;
+ }
case LayerType::Comparison:
{
auto cLayer = PolymorphicDowncast<const ComparisonLayer*>(&layer);
@@ -1345,6 +1355,12 @@ std::unique_ptr<IWorkload> IWorkloadFactory::CreateBatchToSpaceNd(const BatchToS
return std::unique_ptr<IWorkload>();
}
+std::unique_ptr<IWorkload> IWorkloadFactory::CreateCast(const CastQueueDescriptor& /*descriptor*/,
+ const WorkloadInfo& /*info*/) const
+{
+ return std::unique_ptr<IWorkload>();
+}
+
std::unique_ptr<IWorkload> IWorkloadFactory::CreateComparison(const ComparisonQueueDescriptor& /*descriptor*/,
const WorkloadInfo& /*info*/) const
{
diff --git a/src/backends/backendsCommon/WorkloadFactory.hpp b/src/backends/backendsCommon/WorkloadFactory.hpp
index 13fd190ea2..42360d37ff 100644
--- a/src/backends/backendsCommon/WorkloadFactory.hpp
+++ b/src/backends/backendsCommon/WorkloadFactory.hpp
@@ -87,6 +87,9 @@ public:
virtual std::unique_ptr<IWorkload> CreateBatchToSpaceNd(const BatchToSpaceNdQueueDescriptor& descriptor,
const WorkloadInfo& Info) const;
+ virtual std::unique_ptr<IWorkload> CreateCast(const CastQueueDescriptor& descriptor,
+ const WorkloadInfo& Info) const;
+
virtual std::unique_ptr<IWorkload> CreateComparison(const ComparisonQueueDescriptor& descriptor,
const WorkloadInfo& Info) const;
diff --git a/src/backends/backendsCommon/common.mk b/src/backends/backendsCommon/common.mk
index 54c791677f..6e4a8c75d2 100644
--- a/src/backends/backendsCommon/common.mk
+++ b/src/backends/backendsCommon/common.mk
@@ -43,6 +43,7 @@ COMMON_TEST_SOURCES := \
test/layerTests/AdditionTestImpl.cpp \
test/layerTests/ArgMinMaxTestImpl.cpp \
test/layerTests/BatchNormalizationTestImpl.cpp \
+ test/layerTests/CastTestImpl.cpp \
test/layerTests/ComparisonTestImpl.cpp \
test/layerTests/ConcatTestImpl.cpp \
test/layerTests/ConstantTestImpl.cpp \
diff --git a/src/backends/backendsCommon/test/CMakeLists.txt b/src/backends/backendsCommon/test/CMakeLists.txt
index 248ada92a2..98b800bda2 100644
--- a/src/backends/backendsCommon/test/CMakeLists.txt
+++ b/src/backends/backendsCommon/test/CMakeLists.txt
@@ -68,6 +68,8 @@ list(APPEND armnnBackendsCommonUnitTests_sources
layerTests/BatchNormalizationTestImpl.cpp
layerTests/BatchNormalizationTestImpl.hpp
layerTests/BatchToSpaceNdTestImpl.hpp
+ layerTests/CastTestImpl.cpp
+ layerTests/CastTestImpl.hpp
layerTests/ComparisonTestImpl.cpp
layerTests/ComparisonTestImpl.hpp
layerTests/ConcatTestImpl.cpp
diff --git a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
index c7d1dd2182..b73efbe26c 100644
--- a/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
+++ b/src/backends/backendsCommon/test/IsLayerSupportedTestImpl.hpp
@@ -566,6 +566,8 @@ DECLARE_LAYER_POLICY_2_PARAM(BatchNormalization)
DECLARE_LAYER_POLICY_2_PARAM(BatchToSpaceNd)
+DECLARE_LAYER_POLICY_1_PARAM(Cast)
+
DECLARE_LAYER_POLICY_2_PARAM(Comparison)
DECLARE_LAYER_POLICY_2_PARAM(Concat)
diff --git a/src/backends/backendsCommon/test/LayerTests.hpp b/src/backends/backendsCommon/test/LayerTests.hpp
index a7dcb9988f..c1b4b46863 100644
--- a/src/backends/backendsCommon/test/LayerTests.hpp
+++ b/src/backends/backendsCommon/test/LayerTests.hpp
@@ -11,6 +11,7 @@
#include <backendsCommon/test/layerTests/ArgMinMaxTestImpl.hpp>
#include <backendsCommon/test/layerTests/BatchNormalizationTestImpl.hpp>
#include <backendsCommon/test/layerTests/BatchToSpaceNdTestImpl.hpp>
+#include <backendsCommon/test/layerTests/CastTestImpl.hpp>
#include <backendsCommon/test/layerTests/ComparisonTestImpl.hpp>
#include <backendsCommon/test/layerTests/ConcatTestImpl.hpp>
#include <backendsCommon/test/layerTests/ConvertBf16ToFp32TestImpl.hpp>
diff --git a/src/backends/backendsCommon/test/layerTests/CastTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/CastTestImpl.cpp
new file mode 100644
index 0000000000..ad23b8c767
--- /dev/null
+++ b/src/backends/backendsCommon/test/layerTests/CastTestImpl.cpp
@@ -0,0 +1,229 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "CastTestImpl.hpp"
+#include "ElementwiseUnaryTestImpl.hpp"
+
+
+template<armnn::DataType inputDataType, armnn::DataType outputDataType, typename TInput, typename TOutput>
+LayerTestResult<TOutput, 4> CastTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory,
+ const std::vector<TInput>& inputValues,
+ const std::vector<TOutput>& outputValues)
+{
+ IgnoreUnused(memoryManager);
+ armnn::TensorInfo inputTensorInfo({1, 3, 2, 3}, inputDataType);
+ armnn::TensorInfo outputTensorInfo({1, 3, 2, 3}, outputDataType);
+ float quantizationScale = 1.0f;
+ int32_t quantizationOffset = 0;
+
+ if(armnn::IsQuantizedType<TInput>())
+ {
+ inputTensorInfo.SetQuantizationScale(quantizationScale);
+ inputTensorInfo.SetQuantizationOffset(quantizationOffset);
+ }
+ if(armnn::IsQuantizedType<TOutput>())
+ {
+ outputTensorInfo.SetQuantizationScale(quantizationScale);
+ outputTensorInfo.SetQuantizationOffset(quantizationOffset);
+ }
+
+ auto input = MakeTensor<TInput, 4>(inputTensorInfo, inputValues);
+
+ LayerTestResult<TOutput, 4> ret(outputTensorInfo);
+ ret.outputExpected = MakeTensor<TOutput, 4>(outputTensorInfo, outputValues);
+
+ std::unique_ptr<armnn::ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
+ std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
+
+ armnn::CastQueueDescriptor data;
+ armnn::WorkloadInfo info;
+ AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
+ AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
+
+ std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateCast(data, info);
+
+ inputHandle->Allocate();
+ outputHandle->Allocate();
+
+ CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
+
+ workload->Execute();
+
+ CopyDataFromITensorHandle(&ret.output[0][0][0][0], outputHandle.get());
+
+ return ret;
+}
+
+LayerTestResult<float, 4> CastInt32ToFloat2dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int32_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<float> outputValues = { -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.0f, 1.0f, 3.0f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::Signed32, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<float, 4> CastInt16ToFloat2dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int16_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<float> outputValues = { -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.0f, 1.0f, 3.0f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::QSymmS16, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<float, 4> CastInt8ToFloat2dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int8_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<float> outputValues = { -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.0f, 1.0f, 3.0f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::QSymmS8, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<float, 4> CastInt8AsymmToFloat2dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int8_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<float> outputValues = { -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.0f, 1.0f, 3.0f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::QAsymmS8, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues, outputValues);
+}
+
+LayerTestResult<float, 4> CastUInt8ToFloat2dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<u_int8_t> inputValues = { 1, 3, 1, 3, 1, 3, 1, 3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<float> outputValues = { 1.0f, 3.0f, 1.0f, 3.0f, 1.0f, 3.0f, 1.0f, 3.0f, 1.0f,
+ 3.0f, 1.0f, 3.0f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::QAsymmU8, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<uint8_t, 4> CastInt8ToUInt82dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int8_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, -1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<uint8_t> outputValues = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ return CastTest<armnn::DataType::QSymmS8, armnn::DataType::QAsymmU8>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<uint8_t, 4> CastInt8AsymmToUInt82dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<int8_t> inputValues = { -1, -3, -1, -3, -1, -3, -1, -3, -1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ std::vector<uint8_t> outputValues = { 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ return CastTest<armnn::DataType::QAsymmS8, armnn::DataType::QAsymmU8>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<float, 4> CastFloat16ToFloat322dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ using namespace half_float::literal;
+
+ std::vector<armnn::Half> inputValues = { -1.10_h, -3._h, -1.30_h, -3._h, -1._h, -3._h, -1._h, -3._h, 1._h,
+ 3.10_h, 1._h, 3.30_h, 1._h, 2._h, 1._h, 3._h, 1._h, 3._h };
+ std::vector<float> outputValues = { -1.1f, -3.0f, -1.3f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.1f, 1.0f, 3.3f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ return CastTest<armnn::DataType::Float16, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<float, 4> CastBFloat16ToFloat322dTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+
+ std::vector<armnn::BFloat16> inputValues = armnnUtils::QuantizedVector<armnn::BFloat16>(
+ {
+ -37.5f, -15.2f, -8.76f, -2.0f, -1.5f, -1.3f, -0.5f, -0.4f, 0.0f,
+ 1.0f, 0.4f, 0.5f, 1.3f, 1.5f, 2.0f, 8.76f, 15.2f, 37.5f
+ },
+ 1.0f, 0);
+
+
+ std::vector<float> outputValues = { -37.5f, -15.2f, -8.76f, -2.0f, -1.5f, -1.3f, -0.5f, -0.4f, 0.0f,
+ 1.0f, 0.4f, 0.5f, 1.3f, 1.5f, 2.0f, 8.76f, 15.2f, 37.5f };
+
+ return CastTest<armnn::DataType::BFloat16, armnn::DataType::Float32>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues, outputValues);
+}
+
+LayerTestResult<armnn::Half, 4> CastFloat32ToFloat162dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ using namespace half_float::literal;
+
+ std::vector<float> inputValues = { -37.5f, -15.2f, -8.76f, -2.0f, -1.5f, -1.3f, -0.5f, -0.4f,
+ 0.00000004f, 3.4E38f, 300.0f, 0.5f, 1.3f, 1.5f, 2.1E4f, 8.76f, 15.2f, 37.5f };
+ std::vector<armnn::Half> outputValues = {-37.50_h, -15.20_h, -8.76_h, -2._h, -1.50_h, -1.30_h, -0.50_h, -0.40_h,
+ 0._h, 6.55E4_h, 300._h, 0.50_h, 1.30_h, 1.50_h, 2.1E4_h, 8.76_h, 15.20_h, 37.50_h};
+
+ return CastTest<armnn::DataType::Float32, armnn::DataType::Float16>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<int8_t , 4> CastFloat32ToInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<float> inputValues = { -1.0f, -3.5f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.1f, 1.5f, 3.9f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ std::vector<int8_t> outputValues = { -1, -3, -1, -3, -1, -3, -1, -3, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ return CastTest<armnn::DataType::Float32, armnn::DataType::QAsymmS8>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
+
+LayerTestResult<uint8_t , 4> CastFloat32ToUInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory)
+{
+ std::vector<float> inputValues = { -1.0f, -3.5f, -1.0f, -3.0f, -1.0f, -3.0f, -1.0f, -3.0f, 1.0f,
+ 3.1f, 1.5f, 3.9f, 1.0f, 2.0f, 1.0f, 3.0f, 1.0f, 3.0f };
+ std::vector<uint8_t> outputValues = { 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 3, 1, 3, 1, 2, 1, 3, 1, 3 };
+ return CastTest<armnn::DataType::Float32, armnn::DataType::QAsymmU8>(workloadFactory, memoryManager,
+ tensorHandleFactory, inputValues,
+ outputValues);
+}
diff --git a/src/backends/backendsCommon/test/layerTests/CastTestImpl.hpp b/src/backends/backendsCommon/test/layerTests/CastTestImpl.hpp
new file mode 100644
index 0000000000..bf8d5a4e24
--- /dev/null
+++ b/src/backends/backendsCommon/test/layerTests/CastTestImpl.hpp
@@ -0,0 +1,84 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include "LayerTestResult.hpp"
+
+#include <ResolveType.hpp>
+
+#include <armnn/backends/IBackendInternal.hpp>
+#include <backendsCommon/WorkloadFactory.hpp>
+#include <Half.hpp>
+
+template<armnn::DataType inputDataType, armnn::DataType outputDataType,
+ typename TInput=armnn::ResolveType<inputDataType>,
+ typename TOutput=armnn::ResolveType<outputDataType>>
+LayerTestResult<TOutput, 4> CastTest(armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory,
+ const std::vector<TInput>& inputTensor,
+ const std::vector<TOutput>& outputTensor);
+
+
+LayerTestResult<float, 4> CastInt32ToFloat2dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastInt16ToFloat2dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastInt8ToFloat2dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastInt8AsymmToFloat2dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastUInt8ToFloat2dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<uint8_t, 4> CastInt8ToUInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<uint8_t, 4> CastInt8AsymmToUInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastFloat16ToFloat322dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<float, 4> CastBFloat16ToFloat322dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<armnn::Half, 4> CastFloat32ToFloat162dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<int8_t , 4> CastFloat32ToInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
+
+LayerTestResult<uint8_t , 4> CastFloat32ToUInt82dTest(
+ armnn::IWorkloadFactory& workloadFactory,
+ const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
+ const armnn::ITensorHandleFactory& tensorHandleFactory);
diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp
index 2e0a8f2faa..e278e45f01 100644
--- a/src/backends/reference/RefLayerSupport.cpp
+++ b/src/backends/reference/RefLayerSupport.cpp
@@ -303,6 +303,36 @@ bool RefLayerSupport::IsBatchToSpaceNdSupported(const TensorInfo& input,
return supported;
}
+bool RefLayerSupport::IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported) const
+{
+ std::array<DataType, 9> supportedInputTypes =
+ {
+ DataType::BFloat16,
+ DataType::Float32,
+ DataType::Float16,
+ DataType::QSymmS8,
+ DataType::QAsymmS8,
+ DataType::QAsymmU8,
+ DataType::QSymmS16,
+ DataType::Signed32
+ };
+
+ bool supported = true;
+ supported &= CheckSupportRule(TypeAnyOf(input, supportedInputTypes), reasonIfUnsupported,
+ "Reference cast: input is not a supported type");
+
+
+ supported &= CheckSupportRule(TypeAnyOf(output, supportedInputTypes), reasonIfUnsupported,
+ "Reference cast: output is not a supported type");
+
+ supported &= CheckSupportRule(ShapesAreSameTotalSize(input, output), reasonIfUnsupported,
+ "Reference cast: input and output shapes have different number of total elements");
+
+ return supported;
+}
+
bool RefLayerSupport::IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/src/backends/reference/RefLayerSupport.hpp b/src/backends/reference/RefLayerSupport.hpp
index b75b778f7a..7a95bb06ac 100644
--- a/src/backends/reference/RefLayerSupport.hpp
+++ b/src/backends/reference/RefLayerSupport.hpp
@@ -46,6 +46,10 @@ public:
const BatchToSpaceNdDescriptor& descriptor,
Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
+ bool IsCastSupported(const TensorInfo& input,
+ const TensorInfo& output,
+ Optional<std::string&> reasonIfUnsupported = EmptyOptional()) const override;
+
bool IsComparisonSupported(const TensorInfo& input0,
const TensorInfo& input1,
const TensorInfo& output,
diff --git a/src/backends/reference/RefWorkloadFactory.cpp b/src/backends/reference/RefWorkloadFactory.cpp
index fde6c863c3..c1e3d58bd2 100644
--- a/src/backends/reference/RefWorkloadFactory.cpp
+++ b/src/backends/reference/RefWorkloadFactory.cpp
@@ -178,6 +178,12 @@ std::unique_ptr<IWorkload> RefWorkloadFactory::CreateBatchToSpaceNd(const BatchT
return std::make_unique<RefBatchToSpaceNdWorkload>(descriptor, info);
}
+std::unique_ptr<IWorkload> RefWorkloadFactory::CreateCast(const CastQueueDescriptor& descriptor,
+ const WorkloadInfo& info) const
+{
+ return std::make_unique<RefCastWorkload>(descriptor, info);
+}
+
std::unique_ptr<IWorkload> RefWorkloadFactory::CreateComparison(const ComparisonQueueDescriptor& descriptor,
const WorkloadInfo& info) const
{
diff --git a/src/backends/reference/RefWorkloadFactory.hpp b/src/backends/reference/RefWorkloadFactory.hpp
index c22d87fa43..734c5e49c3 100644
--- a/src/backends/reference/RefWorkloadFactory.hpp
+++ b/src/backends/reference/RefWorkloadFactory.hpp
@@ -85,6 +85,9 @@ public:
std::unique_ptr<IWorkload> CreateBatchToSpaceNd(const BatchToSpaceNdQueueDescriptor& descriptor,
const WorkloadInfo& info) const override;
+ std::unique_ptr<IWorkload> CreateCast(const CastQueueDescriptor& descriptor,
+ const WorkloadInfo& info) const override;
+
std::unique_ptr<IWorkload> CreateComparison(const ComparisonQueueDescriptor& descriptor,
const WorkloadInfo& info) const override;
diff --git a/src/backends/reference/backend.mk b/src/backends/reference/backend.mk
index 96765097e4..bf18284143 100644
--- a/src/backends/reference/backend.mk
+++ b/src/backends/reference/backend.mk
@@ -47,6 +47,7 @@ BACKEND_SOURCES := \
workloads/RefArgMinMaxWorkload.cpp \
workloads/RefBatchNormalizationWorkload.cpp \
workloads/RefBatchToSpaceNdWorkload.cpp \
+ workloads/RefCastWorkload.cpp \
workloads/RefComparisonWorkload.cpp \
workloads/RefConcatWorkload.cpp \
workloads/RefConstantWorkload.cpp \
diff --git a/src/backends/reference/test/RefLayerTests.cpp b/src/backends/reference/test/RefLayerTests.cpp
index 7371692d0e..228df0946f 100644
--- a/src/backends/reference/test/RefLayerTests.cpp
+++ b/src/backends/reference/test/RefLayerTests.cpp
@@ -1471,6 +1471,20 @@ ARMNN_AUTO_TEST_CASE_WITH_THF(QLstm, QLstmTest)
ARMNN_AUTO_TEST_CASE_WITH_THF(QLstm1, QLstmTest1)
ARMNN_AUTO_TEST_CASE_WITH_THF(QLstm2, QLstmTest2)
+// Cast
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt32ToFloat, CastInt32ToFloat2dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt16ToFloat, CastInt16ToFloat2dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt8ToFloat, CastInt8ToFloat2dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt8AsymmToFloat, CastInt8AsymmToFloat2dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastUIntToFloat, CastUInt8ToFloat2dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt8ToUInt, CastInt8ToUInt82dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastInt8AsymmToUInt, CastInt8AsymmToUInt82dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastFloat16ToFloat32, CastFloat16ToFloat322dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastBFloat16ToFloat32, CastBFloat16ToFloat322dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastFloatToFloat16, CastFloat32ToFloat162dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastFloatToIn8, CastFloat32ToInt82dTest)
+ARMNN_AUTO_TEST_CASE_WITH_THF(CastFloatToUInt8, CastFloat32ToUInt82dTest)
+
// Convert from BFloat16 to Float32
ARMNN_AUTO_TEST_CASE_WITH_THF(ConvertBf16ToFp32, ConvertBf16ToFp32Test)
diff --git a/src/backends/reference/workloads/CMakeLists.txt b/src/backends/reference/workloads/CMakeLists.txt
index 1f4298be5d..dadedf995a 100644
--- a/src/backends/reference/workloads/CMakeLists.txt
+++ b/src/backends/reference/workloads/CMakeLists.txt
@@ -63,6 +63,8 @@ list(APPEND armnnRefBackendWorkloads_sources
RefBatchNormalizationWorkload.hpp
RefBatchToSpaceNdWorkload.cpp
RefBatchToSpaceNdWorkload.hpp
+ RefCastWorkload.cpp
+ RefCastWorkload.hpp
RefComparisonWorkload.cpp
RefComparisonWorkload.hpp
RefConcatWorkload.cpp
diff --git a/src/backends/reference/workloads/RefCastWorkload.cpp b/src/backends/reference/workloads/RefCastWorkload.cpp
new file mode 100644
index 0000000000..7080415e5d
--- /dev/null
+++ b/src/backends/reference/workloads/RefCastWorkload.cpp
@@ -0,0 +1,40 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "RefCastWorkload.hpp"
+#include "RefWorkloadUtils.hpp"
+#include <armnnUtils/FloatingPointConverter.hpp>
+#include <ResolveType.hpp>
+#include "Encoders.hpp"
+#include "Decoders.hpp"
+
+namespace
+{
+ void Cast(armnn::Decoder<float>& in, armnn::Encoder<float>& out, const uint32_t numElements )
+ {
+ for (unsigned int i = 0; i < numElements; i++)
+ {
+ out.Set(in.Get());
+ ++in;
+ ++out;
+ }
+ }
+}
+
+namespace armnn
+{
+
+ void RefCastWorkload::Execute() const
+ {
+ ARMNN_SCOPED_PROFILING_EVENT(Compute::CpuRef, "RefCastWorkload_Execute");
+ const TensorInfo& inputInfo = GetTensorInfo(m_Data.m_Inputs[0]);
+ const TensorInfo& outputInfo = GetTensorInfo(m_Data.m_Outputs[0]);
+
+ Cast(*MakeDecoder<float>(inputInfo, m_Data.m_Inputs[0]->Map()),
+ *MakeEncoder<float>(outputInfo, m_Data.m_Outputs[0]->Map()),
+ inputInfo.GetNumElements());
+ }
+
+} //namespace armnn \ No newline at end of file
diff --git a/src/backends/reference/workloads/RefCastWorkload.hpp b/src/backends/reference/workloads/RefCastWorkload.hpp
new file mode 100644
index 0000000000..6742ef08ca
--- /dev/null
+++ b/src/backends/reference/workloads/RefCastWorkload.hpp
@@ -0,0 +1,24 @@
+//
+// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#pragma once
+
+#include <backendsCommon/Workload.hpp>
+#include <backendsCommon/WorkloadData.hpp>
+#include "RefWorkloadUtils.hpp"
+
+namespace armnn
+{
+
+
+class RefCastWorkload : public BaseWorkload<CastQueueDescriptor>
+{
+public:
+ using BaseWorkload<CastQueueDescriptor>::BaseWorkload;
+ void Execute() const override;
+};
+
+} //namespace armnn
+
diff --git a/src/backends/reference/workloads/RefWorkloads.hpp b/src/backends/reference/workloads/RefWorkloads.hpp
index 989644f633..d3995f2b82 100644
--- a/src/backends/reference/workloads/RefWorkloads.hpp
+++ b/src/backends/reference/workloads/RefWorkloads.hpp
@@ -18,6 +18,7 @@
#include "RefArgMinMaxWorkload.hpp"
#include "RefBatchNormalizationWorkload.hpp"
#include "RefBatchToSpaceNdWorkload.hpp"
+#include "RefCastWorkload.hpp"
#include "RefComparisonWorkload.hpp"
#include "RefConvolution2dWorkload.hpp"
#include "RefConstantWorkload.hpp"