// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include #include #include "../Serializer.hpp" #include #include #include #include #include #include using armnnDeserializeParser::IDeserializeParser; namespace { armnn::INetworkPtr DeserializeNetwork(const std::string& serializerString) { std::vector const serializerVector{serializerString.begin(), serializerString.end()}; return armnnDeserializeParser::IDeserializeParser::Create()->CreateNetworkFromBinary(serializerVector); } std::string SerializeNetwork(const armnn::INetwork& network) { armnnSerializer::Serializer serializer; serializer.Serialize(network); std::stringstream stream; serializer.SaveSerializedToStream(stream); std::string serializerString{stream.str()}; return serializerString; } } // anonymous namespace BOOST_AUTO_TEST_SUITE(SerializerTests) BOOST_AUTO_TEST_CASE(SimpleNetworkSerialization) { armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0); armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1); armnn::IConnectableLayer* const additionLayer0 = network->AddAdditionLayer(); inputLayer0->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(0)); inputLayer1->GetOutputSlot(0).Connect(additionLayer0->GetInputSlot(1)); armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0); additionLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0)); armnnSerializer::Serializer serializer; serializer.Serialize(*network); std::stringstream stream; serializer.SaveSerializedToStream(stream); BOOST_TEST(stream.str().length() > 0); } BOOST_AUTO_TEST_CASE(Conv2dSerialization) { armnn::IRuntime::CreationOptions options; // default options armnn::IRuntimePtr run = armnn::IRuntime::Create(options); armnnDeserializeParser::IDeserializeParserPtr parser = armnnDeserializeParser::IDeserializeParser::Create(); armnn::TensorInfo inputInfo(armnn::TensorShape({1, 5, 5, 1}), armnn::DataType::Float32, 1.0f, 0); armnn::TensorInfo outputInfo(armnn::TensorShape({1, 3, 3, 1}), armnn::DataType::Float32, 4.0f, 0); armnn::TensorInfo weightsInfo(armnn::TensorShape({1, 3, 3, 1}), armnn::DataType::Float32, 2.0f, 0); std::vector weightsData({4, 5, 6, 0, 0, 0, 3, 2, 1}); // Construct network armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::Convolution2dDescriptor descriptor; descriptor.m_PadLeft = 1; descriptor.m_PadRight = 1; descriptor.m_PadTop = 1; descriptor.m_PadBottom = 1; descriptor.m_StrideX = 2; descriptor.m_StrideY = 2; descriptor.m_BiasEnabled = false; descriptor.m_DataLayout = armnn::DataLayout::NHWC; armnn::ConstTensor weights(weightsInfo, weightsData); armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0, "input"); armnn::IConnectableLayer* const convLayer = network->AddConvolution2dLayer(descriptor, weights, "conv"); armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0, "output"); inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo); convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); armnnSerializer::Serializer serializer; serializer.Serialize(*network); std::stringstream stream; serializer.SaveSerializedToStream(stream); std::string const serializerString{stream.str()}; std::vector const serializerVector{serializerString.begin(), serializerString.end()}; armnn::INetworkPtr deserializedNetwork = parser->CreateNetworkFromBinary(serializerVector); auto deserializedOptimized = Optimize(*deserializedNetwork, {armnn::Compute::CpuRef}, run->GetDeviceSpec()); armnn::NetworkId networkIdentifier; // Load graph into runtime run->LoadNetwork(networkIdentifier, std::move(deserializedOptimized)); std::vector inputData { 1, 5, 2, 3, 5, 8, 7, 3, 6, 3, 3, 3, 9, 1, 9, 4, 1, 8, 1, 3, 6, 8, 1, 9, 2 }; armnn::InputTensors inputTensors { {0, armnn::ConstTensor(run->GetInputTensorInfo(networkIdentifier, 0), inputData.data())} }; std::vector expectedOutputData { 23, 33, 24, 91, 99, 48, 26, 50, 19 }; std::vector outputData(9); armnn::OutputTensors outputTensors { {0, armnn::Tensor(run->GetOutputTensorInfo(networkIdentifier, 0), outputData.data())} }; run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors); BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(), outputData.end(), expectedOutputData.begin(), expectedOutputData.end()); } BOOST_AUTO_TEST_CASE(SimpleNetworkWithMultiplicationSerialization) { const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32); armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer* const inputLayer0 = network->AddInputLayer(0); armnn::IConnectableLayer* const inputLayer1 = network->AddInputLayer(1); const char* multLayerName = "mult_0"; armnn::IConnectableLayer* const multiplicationLayer0 = network->AddMultiplicationLayer(multLayerName); inputLayer0->GetOutputSlot(0).Connect(multiplicationLayer0->GetInputSlot(0)); inputLayer1->GetOutputSlot(0).Connect(multiplicationLayer0->GetInputSlot(1)); armnn::IConnectableLayer* const outputLayer0 = network->AddOutputLayer(0); multiplicationLayer0->GetOutputSlot(0).Connect(outputLayer0->GetInputSlot(0)); armnnSerializer::Serializer serializer; serializer.Serialize(*network); std::stringstream stream; serializer.SaveSerializedToStream(stream); BOOST_TEST(stream.str().length() > 0); BOOST_TEST(stream.str().find(multLayerName) != stream.str().npos); } BOOST_AUTO_TEST_CASE(SimpleReshapeIntegration) { armnn::NetworkId networkIdentifier; armnn::IRuntime::CreationOptions options; // default options armnn::IRuntimePtr run = armnn::IRuntime::Create(options); unsigned int inputShape[] = {1, 9}; unsigned int outputShape[] = {3, 3}; auto inputTensorInfo = armnn::TensorInfo(2, inputShape, armnn::DataType::Float32); auto outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32); auto reshapeOutputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32); armnn::ReshapeDescriptor reshapeDescriptor; reshapeDescriptor.m_TargetShape = reshapeOutputTensorInfo.GetShape(); armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0); armnn::IConnectableLayer *const reshapeLayer = network->AddReshapeLayer(reshapeDescriptor, "ReshapeLayer"); armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0); inputLayer->GetOutputSlot(0).Connect(reshapeLayer->GetInputSlot(0)); inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo); reshapeLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); reshapeLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); armnnSerializer::Serializer serializer; serializer.Serialize(*network); std::stringstream stream; serializer.SaveSerializedToStream(stream); std::string const serializerString{stream.str()}; //Deserialize network. auto deserializedNetwork = DeserializeNetwork(serializerString); //Optimize the deserialized network auto deserializedOptimized = Optimize(*deserializedNetwork, {armnn::Compute::CpuRef}, run->GetDeviceSpec()); // Load graph into runtime run->LoadNetwork(networkIdentifier, std::move(deserializedOptimized)); std::vector input1Data(inputTensorInfo.GetNumElements()); std::iota(input1Data.begin(), input1Data.end(), 8); armnn::InputTensors inputTensors { {0, armnn::ConstTensor(run->GetInputTensorInfo(networkIdentifier, 0), input1Data.data())} }; std::vector outputData(input1Data.size()); armnn::OutputTensors outputTensors { {0,armnn::Tensor(run->GetOutputTensorInfo(networkIdentifier, 0), outputData.data())} }; run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors); BOOST_CHECK_EQUAL_COLLECTIONS(outputData.begin(),outputData.end(), input1Data.begin(),input1Data.end()); } BOOST_AUTO_TEST_CASE(SimpleSoftmaxIntegration) { armnn::TensorInfo tensorInfo({1, 10}, armnn::DataType::Float32); armnn::SoftmaxDescriptor descriptor; descriptor.m_Beta = 1.0f; // Create test network armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0); armnn::IConnectableLayer* const softmaxLayer = network->AddSoftmaxLayer(descriptor, "softmax"); armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0); inputLayer->GetOutputSlot(0).Connect(softmaxLayer->GetInputSlot(0)); inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo); softmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); softmaxLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo); // Serialize & deserialize network armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network)); BOOST_CHECK(deserializedNetwork); armnn::IRuntime::CreationOptions options; armnn::IRuntimePtr runtime = armnn::IRuntime::Create(options); armnn::IOptimizedNetworkPtr optimizedNetwork = armnn::Optimize(*network, {armnn::Compute::CpuRef}, runtime->GetDeviceSpec()); BOOST_CHECK(optimizedNetwork); armnn::IOptimizedNetworkPtr deserializedOptimizedNetwork = armnn::Optimize(*deserializedNetwork, {armnn::Compute::CpuRef}, runtime->GetDeviceSpec()); BOOST_CHECK(deserializedOptimizedNetwork); armnn::NetworkId networkId1; armnn::NetworkId networkId2; runtime->LoadNetwork(networkId1, std::move(optimizedNetwork)); runtime->LoadNetwork(networkId2, std::move(deserializedOptimizedNetwork)); std::vector inputData(tensorInfo.GetNumElements()); std::iota(inputData.begin(), inputData.end(), 0); armnn::InputTensors inputTensors1 { {0, armnn::ConstTensor(runtime->GetInputTensorInfo(networkId1, 0), inputData.data())} }; armnn::InputTensors inputTensors2 { {0, armnn::ConstTensor(runtime->GetInputTensorInfo(networkId2, 0), inputData.data())} }; std::vector outputData1(inputData.size()); std::vector outputData2(inputData.size()); armnn::OutputTensors outputTensors1 { {0, armnn::Tensor(runtime->GetOutputTensorInfo(networkId1, 0), outputData1.data())} }; armnn::OutputTensors outputTensors2 { {0, armnn::Tensor(runtime->GetOutputTensorInfo(networkId2, 0), outputData2.data())} }; runtime->EnqueueWorkload(networkId1, inputTensors1, outputTensors1); runtime->EnqueueWorkload(networkId2, inputTensors2, outputTensors2); BOOST_CHECK_EQUAL_COLLECTIONS(outputData1.begin(), outputData1.end(), outputData2.begin(), outputData2.end()); } BOOST_AUTO_TEST_CASE(SimplePooling2dIntegration) { armnn::NetworkId networkIdentifier; armnn::IRuntime::CreationOptions options; // default options armnn::IRuntimePtr runtime = armnn::IRuntime::Create(options); unsigned int inputShape[] = {1, 2, 2, 1}; unsigned int outputShape[] = {1, 1, 1, 1}; auto inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32); auto outputTensorInfo = armnn::TensorInfo(4, outputShape, armnn::DataType::Float32); armnn::Pooling2dDescriptor desc; desc.m_DataLayout = armnn::DataLayout::NHWC; desc.m_PadTop = 0; desc.m_PadBottom = 0; desc.m_PadLeft = 0; desc.m_PadRight = 0; desc.m_PoolType = armnn::PoolingAlgorithm::Average; desc.m_OutputShapeRounding = armnn::OutputShapeRounding::Floor; desc.m_PaddingMethod = armnn::PaddingMethod::Exclude; desc.m_PoolHeight = 2; desc.m_PoolWidth = 2; desc.m_StrideX = 2; desc.m_StrideY = 2; armnn::INetworkPtr network = armnn::INetwork::Create(); armnn::IConnectableLayer *const inputLayer = network->AddInputLayer(0); armnn::IConnectableLayer *const pooling2dLayer = network->AddPooling2dLayer(desc, "ReshapeLayer"); armnn::IConnectableLayer *const outputLayer = network->AddOutputLayer(0); inputLayer->GetOutputSlot(0).Connect(pooling2dLayer->GetInputSlot(0)); inputLayer->GetOutputSlot(0).SetTensorInfo(inputTensorInfo); pooling2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); pooling2dLayer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo); auto deserializeNetwork = DeserializeNetwork(SerializeNetwork(*network)); //Optimize the deserialized network auto deserializedOptimized = Optimize(*deserializeNetwork, {armnn::Compute::CpuRef}, runtime->GetDeviceSpec()); // Load graph into runtime runtime->LoadNetwork(networkIdentifier, std::move(deserializedOptimized)); std::vector input1Data(inputTensorInfo.GetNumElements()); std::iota(input1Data.begin(), input1Data.end(), 4); armnn::InputTensors inputTensors { {0, armnn::ConstTensor(runtime->GetInputTensorInfo(networkIdentifier, 0), input1Data.data())} }; std::vector outputData(input1Data.size()); armnn::OutputTensors outputTensors { {0, armnn::Tensor(runtime->GetOutputTensorInfo(networkIdentifier, 0), outputData.data())} }; runtime->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors); BOOST_CHECK_EQUAL(outputData[0], 5.5); } BOOST_AUTO_TEST_SUITE_END()