1 // 2 // Copyright © 2017, 2023 Arm Ltd. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #include "ClWorkloadFactoryHelper.hpp" 7 8 #include <Network.hpp> 9 10 #include <GraphUtils.hpp> 11 12 #include <cl/ClWorkloadFactory.hpp> 13 #include <cl/ClBackendContext.hpp> 14 15 #include <armnnUtils/Filesystem.hpp> 16 17 #include <doctest/doctest.h> 18 19 TEST_SUITE("ClOptimizedNetwork") 20 { 21 TEST_CASE("OptimizeValidateGpuDeviceSupportLayerNoFallback") 22 { 23 // build up the structure of the network 24 armnn::INetworkPtr net(armnn::INetwork::Create()); 25 26 armnn::IConnectableLayer* input = net->AddInputLayer(0); 27 armnn::IConnectableLayer* output = net->AddOutputLayer(0); 28 29 input->GetOutputSlot(0).Connect(output->GetInputSlot(0)); 30 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32)); 31 32 armnn::IRuntime::CreationOptions options; 33 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); 34 35 std::vector<armnn::BackendId> backends = { armnn::Compute::GpuAcc }; 36 armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*net, backends, runtime->GetDeviceSpec()); 37 CHECK(optNet); 38 // validate workloads 39 armnn::ClWorkloadFactory fact = 40 ClWorkloadFactoryHelper::GetFactory(ClWorkloadFactoryHelper::GetMemoryManager()); 41 42 const armnn::Graph& theGraph = GetGraphForTesting(optNet.get()); 43 for (auto&& layer : theGraph) 44 { 45 CHECK(layer->GetBackendId() == armnn::Compute::GpuAcc); 46 CHECK_NOTHROW( 47 layer->CreateWorkload(fact)); 48 } 49 } 50 51 TEST_CASE("FP16TurboModeTestOnGpuAcc") 52 { 53 // Test to check when Fp16 Turbo mode set 54 // it converts the Fp32 network to Fp16 Network 55 // add Fp32ToFp16 conversion layer after the InputLayer 56 // add Fp16ToFp32 conversion layer after the OutputLayer 57 // checks the other layers if they are supported in Fp16 58 // if they are not put the conversion layers before and after 59 // if they are not supported in Fp16 use Fp32 instead 60 // if there are inverse conversion layers remove them with optimization 61 // at the moment FloorLayer is not supported in Fp16 so it rolls back to Fp32 62 // and inverse conversion layers are removed by the optimizer 63 armnn::INetworkPtr net(armnn::INetwork::Create()); 64 65 // Defines layers. 66 auto input = net->AddInputLayer(0, "input layer"); 67 // ReLu1 68 armnn::ActivationDescriptor activation1Descriptor; 69 activation1Descriptor.m_Function = armnn::ActivationFunction::BoundedReLu; 70 activation1Descriptor.m_A = 1.f; 71 activation1Descriptor.m_B = -1.f; 72 auto activation = net->AddActivationLayer(activation1Descriptor, "activation layer"); 73 auto output = net->AddOutputLayer(0, "output layer"); 74 75 // Connects layers. 76 input->GetOutputSlot(0).Connect(activation->GetInputSlot(0)); 77 activation->GetOutputSlot(0).Connect(output->GetInputSlot(0)); 78 79 armnn::TensorShape shape({4}); 80 armnn::TensorInfo info(shape, armnn::DataType::Float32); 81 input->GetOutputSlot(0).SetTensorInfo(info); 82 activation->GetOutputSlot(0).SetTensorInfo(info); 83 84 armnn::IRuntime::CreationOptions options; 85 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); 86 87 std::vector<armnn::BackendId> backends = {armnn::Compute::GpuAcc}; 88 89 armnn::OptimizerOptionsOpaque optimizerOptions; 90 optimizerOptions.SetReduceFp32ToFp16(true); 91 92 armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize( 93 *net, backends, runtime->GetDeviceSpec(), optimizerOptions); 94 95 const armnn::Graph& graph = GetGraphForTesting(optimizedNet.get()); 96 97 // Tests that all layers are present in the graph. 98 CHECK(graph.GetNumLayers() == 5); 99 100 // Tests that the vertices exist and have correct names. 101 CHECK(GraphHasNamedLayer(graph, "input layer")); 102 CHECK(GraphHasNamedLayer(graph, "convert_fp32_to_fp16-0-input layer")); 103 CHECK(GraphHasNamedLayer(graph, "activation layer")); 104 CHECK(GraphHasNamedLayer(graph, "convert_fp16_to_fp32-0-output layer")); 105 CHECK(GraphHasNamedLayer(graph, "output layer")); 106 } 107 108 TEST_CASE("FastMathEnabledTestOnGpuAcc") 109 { 110 armnn::INetworkPtr net(armnn::INetwork::Create()); 111 112 armnn::IConnectableLayer* input = net->AddInputLayer(0); 113 armnn::IConnectableLayer* output = net->AddOutputLayer(0); 114 115 input->GetOutputSlot(0).Connect(output->GetInputSlot(0)); 116 input->GetOutputSlot(0).SetTensorInfo(armnn::TensorInfo({ 1, 1, 4, 4 }, armnn::DataType::Float32)); 117 118 armnn::IRuntime::CreationOptions options; 119 armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); 120 121 std::vector<armnn::BackendId> backends = {armnn::Compute::GpuAcc}; 122 armnn::OptimizerOptionsOpaque optimizerOptions; 123 armnn::BackendOptions modelOptions("GpuAcc", {{"FastMathEnabled", true}}); 124 optimizerOptions.AddModelOption(modelOptions); 125 126 armnn::IOptimizedNetworkPtr optimizedNet = armnn::Optimize( 127 *net, backends, runtime->GetDeviceSpec(), optimizerOptions); 128 129 CHECK(optimizedNet); 130 131 auto modelOptionsOut = GetModelOptionsForTesting(optimizedNet.get()); 132 133 CHECK(modelOptionsOut.size() == 2); // FastMathEnabled and the Global to hold the import export values. 134 CHECK(modelOptionsOut[0].GetOption(0).GetName() == "FastMathEnabled"); 135 CHECK(modelOptionsOut[0].GetOption(0).GetValue().AsBool() == true); 136 } 137 138 TEST_CASE("CheckMLGOTuningFile") 139 { 140 class ClBackendContextTestClass : public armnn::ClBackendContext 141 { 142 public: ClBackendContextTestClass(const armnn::IRuntime::CreationOptions & options)143 ClBackendContextTestClass(const armnn::IRuntime::CreationOptions &options) : ClBackendContext(options) 144 {} 145 call_reload_from_file()146 bool call_reload_from_file() 147 { 148 return m_MLGOTuner.reload_from_file(m_MLGOTuningFile); 149 } 150 }; 151 152 const std::string validText{ 153 "<header>\n" 154 "gemm-version, [1,2,1]\n" 155 "ip-type,gpu\n" 156 "</header>\n" 157 "<heuristics-table>\n" 158 "0, g71 , 8, f32, best-performance, static, gemm-type, [m,n,k,n]\n" 159 "1, g71 , 8, f32, best-performance, static, gemm-config-reshaped-only-rhs, [m,n,k,n]\n" 160 "2, g71 , 8, f32, best-performance, static, gemm-config-reshaped, [m,n,k,n]\n" 161 "3, g71 , 8, qasymm8, best-performance, static, gemm-type, [m,n,k,n]\n" 162 "4, g71 , 8, qasymm8, best-performance, static, gemm-config-reshaped-only-rhs, [m,n,k,n]\n" 163 "5, g71 , 8, qasymm8, best-performance, static, gemm-config-native, [m,n,k,n]\n" 164 "</heuristics-table>\n" 165 "<heuristic, 0>\n" 166 "b , 0, var, r_mn, >=, num, 2., 1, 2\n" 167 "l , 1, gemm-type, reshaped\n" 168 "l , 2, gemm-type, reshaped-only-rhs\n" 169 "</heuristic>\n" 170 "<heuristic, 1>\n" 171 "l ,0,gemm-config-reshaped-only-rhs, [2, 4,4,4,1,1,0]\n" 172 "</heuristic>\n" 173 "<heuristic, 2>\n" 174 "l ,0,gemm-config-reshaped,[4,2,8,16,16,1,0,1,0]\n" 175 "</heuristic>\n" 176 "<heuristic, 3>\n" 177 "l , 0, gemm-type, native\n" 178 "</heuristic>\n" 179 "<heuristic, 4>\n" 180 "l ,0,gemm-config-reshaped-only-rhs, [2, 4,4,4,1,1,0]\n" 181 "</heuristic>\n" 182 "<heuristic, 5>\n" 183 "l ,0,gemm-config-native,[4,2,8]\n" 184 "</heuristic>\n"}; 185 186 const std::string invalidText{"ʕノ•ᴥ•ʔノ ︵ ┻━┻"}; 187 188 fs::path validFile = armnnUtils::Filesystem::NamedTempFile("validFile.mlgo"); 189 fs::path invalidFile = armnnUtils::Filesystem::NamedTempFile("invalidFile.mlgo"); 190 191 try 192 { 193 std::ofstream ofs1{validFile}; 194 ofs1 << validText << std::endl; 195 ofs1.close(); 196 197 std::ofstream ofs2{invalidFile}; 198 ofs2 << invalidText << std::endl; 199 ofs2.close(); 200 } 201 catch (std::exception &e) 202 { 203 std::cerr << "Unable to write to file at location [" << validFile.c_str() << "] : " << e.what() << std::endl; 204 CHECK(false); 205 } 206 207 armnn::IRuntime::CreationOptions creationOptions1; 208 armnn::BackendOptions validOptions 209 { 210 "GpuAcc", 211 { 212 {"MLGOTuningFilePath", validFile.c_str()} 213 } 214 }; 215 216 creationOptions1.m_BackendOptions.emplace_back(validOptions); 217 ClBackendContextTestClass clBackendContext1(creationOptions1); 218 CHECK(clBackendContext1.call_reload_from_file()); 219 220 armnn::BackendOptions invalidOptions 221 { 222 "GpuAcc", 223 { 224 {"MLGOTuningFilePath", invalidFile.c_str()} 225 } 226 }; 227 228 armnn::IRuntime::CreationOptions creationOptions2; 229 creationOptions2.m_BackendOptions.emplace_back(invalidOptions); 230 ClBackendContextTestClass clBackendContext2(creationOptions2); 231 CHECK(clBackendContext2.call_reload_from_file() == false); 232 233 armnn::BackendOptions invalidPathOptions 234 { 235 "GpuAcc", 236 { 237 {"MLGOTuningFilePath", "not_a_real_file_path"} 238 } 239 }; 240 241 armnn::IRuntime::CreationOptions creationOptions3; 242 creationOptions3.m_BackendOptions.emplace_back(invalidPathOptions); 243 ClBackendContextTestClass clBackendContext3(creationOptions3); 244 CHECK(clBackendContext3.call_reload_from_file() == false); 245 } 246 247 } 248