From e7cc7c32165220446b58bed24b6d37e41fc506d0 Mon Sep 17 00:00:00 2001 From: Jan Eilers Date: Thu, 25 Jun 2020 13:18:47 +0100 Subject: IVGCVSW-4910 Productise YoloV3 Big App * use cxxopts to process program arguments * remove hard coded paths for models * added options for preferred backends for each model Signed-off-by: Jan Eilers Change-Id: I74a89577e15c4828e8b522bbf1f65f1895cdd657 --- .../TfLiteYoloV3Big-Armnn.cpp | 154 ++++++++++++++++++--- 1 file changed, 138 insertions(+), 16 deletions(-) (limited to 'tests') diff --git a/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp b/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp index 1905e9002d..4610675237 100644 --- a/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp +++ b/tests/TfLiteYoloV3Big-Armnn/TfLiteYoloV3Big-Armnn.cpp @@ -2,8 +2,7 @@ // Copyright © 2020 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // -//#include "../InferenceTest.hpp" -//#include "../ImagePreprocessor.hpp" + #include "armnnTfLiteParser/ITfLiteParser.hpp" #include "NMS.hpp" @@ -15,9 +14,13 @@ #include #include +#include +#include + #include -#include #include +#include +#include using namespace armnnTfLiteParser; using namespace armnn; @@ -175,23 +178,143 @@ std::vector LoadImage(const char* filename) return image; } -int main(int argc, char* argv[]) + +bool ValidateFilePath(std::string& file) +{ + if (!ghc::filesystem::exists(file)) + { + std::cerr << "Given file path " << file << " does not exist" << std::endl; + return false; + } + if (!ghc::filesystem::is_regular_file(file)) + { + std::cerr << "Given file path " << file << " is not a regular file" << std::endl; + return false; + } + return true; +} + + +struct ParseArgs { - if (argc != 3) + ParseArgs(int ac, char *av[]) : options{"TfLiteYoloV3Big-Armnn", + "Executes YoloV3Big using ArmNN. YoloV3Big consists " + "of 3 parts: A backbone TfLite model, a detector TfLite " + "model, and None Maximum Suppression. All parts are " + "executed successively."} + { + options.add_options() + ("b,backbone-path", + "File path where the TfLite model for the yoloV3big backbone " + "can be found e.g. mydir/yoloV3big_backbone.tflite", + cxxopts::value()) + + ("d,detector-path", + "File path where the TfLite model for the yoloV3big " + "detector can be found e.g.'mydir/yoloV3big_detector.tflite'", + cxxopts::value()) + + ("h,help", "Produce help message") + + ("i,image-path", + "File path to a 1080x1920 jpg image that should be " + "processed e.g. 'mydir/example_img_180_1920.jpg'", + cxxopts::value()) + + ("B,preferred-backends-backbone", + "Defines the preferred backends to run the backbone model " + "of yoloV3big e.g. 'GpuAcc,CpuRef' -> GpuAcc will be tried " + "first before falling back to CpuRef. NOTE: Backends are passed " + "as comma separated list without whitespaces.", + cxxopts::value>()->default_value("GpuAcc,CpuRef")) + + ("D,preferred-backends-detector", + "Defines the preferred backends to run the detector model " + "of yoloV3big e.g. 'CpuAcc,CpuRef' -> CpuAcc will be tried " + "first before falling back to CpuRef. NOTE: Backends are passed " + "as comma separated list without whitespaces.", + cxxopts::value>()->default_value("CpuAcc,CpuRef")); + + auto result = options.parse(ac, av); + + if (result.count("help")) + { + std::cout << options.help() << "\n"; + exit(EXIT_SUCCESS); + } + + backboneDir = GetPathArgument(result, "backbone-path"); + detectorDir = GetPathArgument(result, "detector-path"); + imageDir = GetPathArgument(result, "image-path"); + + prefBackendsBackbone = GetBackendIDs(result["preferred-backends-backbone"].as>()); + LogBackendsInfo(prefBackendsBackbone, "Backbone"); + prefBackendsDetector = GetBackendIDs(result["preferred-backends-detector"].as>()); + LogBackendsInfo(prefBackendsDetector, "detector"); + } + + /// Takes a vector of backend strings and returns a vector of backendIDs + std::vector GetBackendIDs(const std::vector& backendStrings) + { + std::vector backendIDs; + for (const auto& b : backendStrings) + { + backendIDs.push_back(BackendId(b)); + } + return backendIDs; + } + + /// Verifies if the program argument with the name argName contains a valid file path. + /// Returns the valid file path string if given argument is associated a valid file path. + /// Otherwise throws an exception. + std::string GetPathArgument(cxxopts::ParseResult& result, std::string&& argName) + { + if (result.count(argName)) + { + std::string fileDir = result[argName].as(); + if (!ValidateFilePath(fileDir)) + { + throw cxxopts::option_syntax_exception("Argument given to backbone-path is not a valid file path"); + } + return fileDir; + } + else + { + throw cxxopts::missing_argument_exception(argName); + } + } + + /// Log info about assigned backends + void LogBackendsInfo(std::vector& backends, std::string&& modelName) { - ARMNN_LOG(error) << "Expected arguments: {PathToModels} {PathToData}"; + std::string info; + info = "Preferred backends for " + modelName + " set to [ "; + for (auto const &backend : backends) + { + info = info + std::string(backend) + " "; + } + ARMNN_LOG(info) << info << "]"; } - std::string modelsPath(argv[1]); - std::string imagePath(argv[2]); - std::string backboneModelFile = modelsPath + "yolov3_1080_1920_backbone_int8.tflite"; - std::string detectorModelFile = modelsPath + "yolov3_1080_1920_detector_fp32.tflite"; - std::string imageFile = imagePath + "1080_1920.jpg"; + // Member variables + std::string backboneDir; + std::string detectorDir; + std::string imageDir; - // Configure the logging + std::vector prefBackendsBackbone; + std::vector prefBackendsDetector; + + cxxopts::Options options; +}; + +int main(int argc, char* argv[]) +{ + // Configure logging SetAllLoggingSinks(true, true, true); SetLogFilter(LogSeverity::Trace); + // Check and get given program arguments + ParseArgs progArgs = ParseArgs(argc, argv); // Create runtime IRuntime::CreationOptions runtimeOptions; // default @@ -209,7 +332,7 @@ int main(int argc, char* argv[]) // Load backbone model ARMNN_LOG(info) << "Loading backbone..."; NetworkId backboneId; - CHECK_OK(LoadModel(backboneModelFile.c_str(), *parser, *runtime, backboneId, {"GpuAcc", "CpuRef"})); + CHECK_OK(LoadModel(progArgs.backboneDir.c_str(), *parser, *runtime, backboneId, progArgs.prefBackendsBackbone)); auto inputId = parser->GetNetworkInputBindingInfo(0, "inputs"); auto bbOut0Id = parser->GetNetworkOutputBindingInfo(0, "input_to_detector_1"); auto bbOut1Id = parser->GetNetworkOutputBindingInfo(0, "input_to_detector_2"); @@ -220,7 +343,7 @@ int main(int argc, char* argv[]) // Load detector model ARMNN_LOG(info) << "Loading detector..."; NetworkId detectorId; - CHECK_OK(LoadModel(detectorModelFile.c_str(), *parser, *runtime, detectorId, {"CpuAcc", "CpuRef"})); + CHECK_OK(LoadModel(progArgs.detectorDir.c_str(), *parser, *runtime, detectorId, progArgs.prefBackendsDetector)); auto detectIn0Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_1"); auto detectIn1Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_2"); auto detectIn2Id = parser->GetNetworkInputBindingInfo(0, "input_to_detector_3"); @@ -229,13 +352,12 @@ int main(int argc, char* argv[]) // Load input from file ARMNN_LOG(info) << "Loading test image..."; - auto image = LoadImage(imageFile.c_str()); + auto image = LoadImage(progArgs.imageDir.c_str()); if (image.empty()) { return LOAD_IMAGE_ERROR; } - // Allocate the intermediate tensors std::vector intermediateMem0(bbOut0Id.second.GetNumElements()); std::vector intermediateMem1(bbOut1Id.second.GetNumElements()); -- cgit v1.2.1