// // Copyright © 2017 Arm Ltd. All rights reserved. // SPDX-License-Identifier: MIT // #include #include #include #include #include #include "armnn/ArmNN.hpp" #include "armnn/Utils.hpp" #include "armnn/INetwork.hpp" #include "armnnCaffeParser/ICaffeParser.hpp" #include "../Cifar10Database.hpp" #include "../InferenceTest.hpp" #include "../InferenceModel.hpp" using namespace std; using namespace std::chrono; using namespace armnn::test; int main(int argc, char* argv[]) { #ifdef NDEBUG armnn::LogSeverity level = armnn::LogSeverity::Info; #else armnn::LogSeverity level = armnn::LogSeverity::Debug; #endif try { // Configures logging for both the ARMNN library and this test program. armnn::ConfigureLogging(true, true, level); armnnUtils::ConfigureLogging(boost::log::core::get().get(), true, true, level); namespace po = boost::program_options; std::vector computeDevice; std::string modelDir; std::string dataDir; po::options_description desc("Options"); try { // Adds generic options needed for all inference tests. desc.add_options() ("help", "Display help messages") ("model-dir,m", po::value(&modelDir)->required(), "Path to directory containing the Cifar10 model file") ("compute,c", po::value>(&computeDevice)->default_value ({armnn::Compute::CpuAcc, armnn::Compute::CpuRef}), "Which device to run layers on by default. Possible choices: CpuAcc, CpuRef, GpuAcc") ("data-dir,d", po::value(&dataDir)->required(), "Path to directory containing the Cifar10 test data"); } catch (const std::exception& e) { // Coverity points out that default_value(...) can throw a bad_lexical_cast, // and that desc.add_options() can throw boost::io::too_few_args. // They really won't in any of these cases. BOOST_ASSERT_MSG(false, "Caught unexpected exception"); std::cerr << "Fatal internal error: " << e.what() << std::endl; return 1; } po::variables_map vm; try { po::store(po::parse_command_line(argc, argv, desc), vm); if (vm.count("help")) { std::cout << desc << std::endl; return 1; } po::notify(vm); } catch (po::error& e) { std::cerr << e.what() << std::endl << std::endl; std::cerr << desc << std::endl; return 1; } if (!ValidateDirectory(modelDir)) { return 1; } string modelPath = modelDir + "cifar10_full_iter_60000.caffemodel"; // Create runtime armnn::IRuntime::CreationOptions options; armnn::IRuntimePtr runtime(armnn::IRuntime::Create(options)); // Loads networks. armnn::Status status; struct Net { Net(armnn::NetworkId netId, const std::pair& in, const std::pair& out) : m_Network(netId) , m_InputBindingInfo(in) , m_OutputBindingInfo(out) {} armnn::NetworkId m_Network; std::pair m_InputBindingInfo; std::pair m_OutputBindingInfo; }; std::vector networks; armnnCaffeParser::ICaffeParserPtr parser(armnnCaffeParser::ICaffeParser::Create()); const int networksCount = 4; for (int i = 0; i < networksCount; ++i) { // Creates a network from a file on the disk. armnn::INetworkPtr network = parser->CreateNetworkFromBinaryFile(modelPath.c_str(), {}, { "prob" }); // Optimizes the network. armnn::IOptimizedNetworkPtr optimizedNet(nullptr, nullptr); try { optimizedNet = armnn::Optimize(*network, computeDevice, runtime->GetDeviceSpec()); } catch (armnn::Exception& e) { std::stringstream message; message << "armnn::Exception ("<LoadNetwork(networkId, std::move(optimizedNet)); if (status == armnn::Status::Failure) { BOOST_LOG_TRIVIAL(fatal) << "armnn::IRuntime: Failed to load network"; return 1; } networks.emplace_back(networkId, parser->GetNetworkInputBindingInfo("data"), parser->GetNetworkOutputBindingInfo("prob")); } // Loads a test case and tests inference. if (!ValidateDirectory(dataDir)) { return 1; } Cifar10Database cifar10(dataDir); for (unsigned int i = 0; i < 3; ++i) { // Loads test case data (including image data). std::unique_ptr testCaseData = cifar10.GetTestCaseData(i); // Tests inference. std::vector> outputs(networksCount); for (unsigned int k = 0; k < networksCount; ++k) { status = runtime->EnqueueWorkload(networks[k].m_Network, MakeInputTensors(networks[k].m_InputBindingInfo, testCaseData->m_InputImage), MakeOutputTensors(networks[k].m_OutputBindingInfo, outputs[k])); if (status == armnn::Status::Failure) { BOOST_LOG_TRIVIAL(fatal) << "armnn::IRuntime: Failed to enqueue workload"; return 1; } } // Compares outputs. for (unsigned int k = 1; k < networksCount; ++k) { if (!std::equal(outputs[0].begin(), outputs[0].end(), outputs[k].begin(), outputs[k].end())) { BOOST_LOG_TRIVIAL(error) << "Multiple networks inference failed!"; return 1; } } } BOOST_LOG_TRIVIAL(info) << "Multiple networks inference ran successfully!"; return 0; } catch (armnn::Exception const& e) { // Coverity fix: BOOST_LOG_TRIVIAL (typically used to report errors) may throw an // exception of type std::length_error. // Using stderr instead in this context as there is no point in nesting try-catch blocks here. std::cerr << "Armnn Error: " << e.what() << std::endl; return 1; } catch (const std::exception& e) { // Coverity fix: various boost exceptions can be thrown by methods called by this test. std::cerr << "WARNING: MultipleNetworksCifar10: An error has occurred when running the " "multiple networks inference tests: " << e.what() << std::endl; return 1; } }