1 // 2 // Copyright © 2022 Arm Ltd and Contributors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #include <TestUtils.hpp> 7 8 #include <Half.hpp> 9 #include <Optimizer.hpp> 10 11 #include <doctest/doctest.h> 12 13 using namespace armnn; 14 15 TEST_SUITE("Optimizer") 16 { 17 using namespace armnn::optimizations; 18 19 TEST_CASE("ConvertConstantsFloatToHalfTest") 20 { 21 armnn::Graph graph; 22 23 const armnn::TensorInfo info({ 1, 1, 1, 2 }, armnn::DataType::Float16); 24 25 // Create const tensor from fp32 data 26 unsigned int dims[] = { 4, 1, 1, 1 }; 27 std::vector<float> floatWeights{ 1.0f, 2.0f, 3.0f, 4.0f }; 28 armnn::TensorInfo weightsInfo = armnn::TensorInfo(4, dims, armnn::DataType::Float32, 0.0f, 0, true); 29 armnn::ConstTensor weights(weightsInfo, floatWeights); 30 31 // Create simple test network 32 auto input = graph.AddLayer<armnn::InputLayer>(0, "input"); 33 input->GetOutputSlot().SetTensorInfo(info); 34 35 auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc"); 36 fc->GetOutputSlot().SetTensorInfo(info); 37 38 auto weightsLayer = graph.AddLayer<armnn::ConstantLayer>("weights"); 39 weightsLayer->m_LayerOutput = std::make_unique<armnn::ScopedTensorHandle>(weights); 40 weightsLayer->GetOutputSlot().SetTensorInfo(weightsInfo); 41 42 auto output = graph.AddLayer<armnn::OutputLayer>(1, "output"); 43 44 // Connect up the layers 45 input->GetOutputSlot().Connect(fc->GetInputSlot(0)); 46 weightsLayer->GetOutputSlot().Connect(fc->GetInputSlot(1)); 47 fc->GetOutputSlot().Connect(output->GetInputSlot(0)); 48 49 // Check tensor data type before conversion 50 CHECK(weightsLayer->m_LayerOutput->GetTensorInfo().GetDataType() == armnn::DataType::Float32); 51 52 // Run the optimizer 53 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsFloatToHalf())); 54 55 // Check tensor data type after conversion 56 CHECK(weightsLayer->m_LayerOutput->GetTensorInfo().GetDataType() == armnn::DataType::Float16); 57 58 // Check whether data matches expected fp16 data 59 const Half* data = weightsLayer->m_LayerOutput->GetConstTensor<Half>(); 60 CHECK(data[0] == Half(1.0f)); 61 CHECK(data[1] == Half(2.0f)); 62 CHECK(data[2] == Half(3.0f)); 63 CHECK(data[3] == Half(4.0f)); 64 } 65 66 67 TEST_CASE("ConvertConstantsFloatToHalfTest_constant") 68 { 69 armnn::Graph graph; 70 71 // Create the simple test network with Weights and Biases as inputs to a FullyConnected layer. 72 auto input = graph.AddLayer<armnn::InputLayer>(0, "Input"); 73 auto weights = graph.AddLayer<armnn::ConstantLayer>("Weights"); 74 auto biases = graph.AddLayer<armnn::ConstantLayer>("Biases"); 75 76 armnn::FullyConnectedDescriptor desc; 77 desc.m_BiasEnabled = true; 78 desc.m_ConstantWeights = true; 79 auto fcLayer = graph.AddLayer<armnn::FullyConnectedLayer>(desc, "FullyConnected"); 80 auto output = graph.AddLayer<armnn::OutputLayer>(1, "Output"); 81 82 float expectedWeightsData[] = { 1.0f, 2.0f, 3.0f, 4.0f }; 83 float expectedBiasesData[] = { 2.0f, 2.0f }; 84 85 const armnn::TensorInfo inputInfo ({ 1, 2, 2, 3 }, armnn::DataType::Float16); 86 const armnn::TensorInfo outputInfo ({ 1, 2, 2, 3 }, armnn::DataType::Float16); 87 const armnn::TensorInfo weightsInfo({ 4 }, armnn::DataType::Float32, 0.0f, 0, true); 88 const armnn::TensorInfo biasesInfo ({ 2 }, armnn::DataType::Float32, 0.0f, 0, true); 89 90 // Set the m_LayerOutput for the optimizer to point to. 91 armnn::ConstTensor weightsTensor(weightsInfo, &expectedWeightsData); 92 armnn::ConstTensor biasesTensor(biasesInfo, &expectedBiasesData); 93 weights->m_LayerOutput = std::make_unique<armnn::ScopedTensorHandle>(weightsTensor); 94 biases->m_LayerOutput = std::make_unique<armnn::ScopedTensorHandle>(biasesTensor); 95 96 input->GetOutputSlot().SetTensorInfo(inputInfo); 97 weights->GetOutputSlot().SetTensorInfo(weightsInfo); 98 biases->GetOutputSlot().SetTensorInfo(biasesInfo); 99 fcLayer->GetOutputSlot().SetTensorInfo(outputInfo); 100 101 // Connect up the layers 102 input->GetOutputSlot(0).Connect(fcLayer->GetInputSlot(0)); 103 weights->GetOutputSlot(0).Connect(fcLayer->GetInputSlot(1)); 104 biases->GetOutputSlot(0).Connect(fcLayer->GetInputSlot(2)); 105 fcLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0)); 106 107 // Check tensor data type before conversion 108 CHECK(5 == graph.GetNumLayers()); 109 CHECK(weights->m_LayerOutput->GetTensorInfo().GetDataType() == armnn::DataType::Float32); 110 111 // Run the optimizer 112 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsFloatToHalf())); 113 114 // Check tensor data type after conversion 115 CHECK(5 == graph.GetNumLayers()); 116 CHECK(weights->m_LayerOutput->GetTensorInfo().GetDataType() == armnn::DataType::Float16); 117 118 // Check whether weights data matches expected fp16 data 119 const Half* data = weights->m_LayerOutput->GetConstTensor<Half>(); 120 CHECK(data[0] == Half(1.0f)); 121 CHECK(data[1] == Half(2.0f)); 122 CHECK(data[2] == Half(3.0f)); 123 CHECK(data[3] == Half(4.0f)); 124 125 // Check whether bias data matches expected fp16 data 126 const Half* biasData = biases->m_LayerOutput->GetConstTensor<Half>(); 127 CHECK(biasData[0] == Half(2.0f)); 128 CHECK(biasData[1] == Half(2.0f)); 129 } 130 131 132 }