diff --git a/.gitmodules b/.gitmodules index d1470c208..46a44c8fa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,7 @@ path = src/cpp_dl_benchmark/thirdparty/gflags url = https://github.com/gflags/gflags.git branch = master +[submodule "src/output_processing/thirdparty/pybind11"] + path = src/output_processing/thirdparty/pybind11 + url = https://github.com/pybind/pybind11.git + branch = master diff --git a/src/output_processing/CMakeLists.txt b/src/output_processing/CMakeLists.txt new file mode 100644 index 000000000..b49fcae66 --- /dev/null +++ b/src/output_processing/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.13) + +project(output_processing_lib CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") + +file(GLOB_RECURSE HEADERS "${CMAKE_CURRENT_SOURCE_DIR}/include/*") +file(GLOB_RECURSE SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/*") + +file(GLOB_RECURSE PY_SOURCES ${HEADERS} ${SOURCES} output_processing.cpp wrappers.hpp) + +add_subdirectory(thirdparty/pybind11) + +pybind11_add_module(${PROJECT_NAME}_py MODULE ${PY_SOURCES}) +add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES}) + +target_include_directories(${PROJECT_NAME}_py PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") +target_include_directories(${PROJECT_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") diff --git a/src/output_processing/include/output_processing/exception_handler.hpp b/src/output_processing/include/output_processing/exception_handler.hpp new file mode 100644 index 000000000..bf463fe94 --- /dev/null +++ b/src/output_processing/include/output_processing/exception_handler.hpp @@ -0,0 +1,5 @@ +#pragma once + +#define DLB_ASSERT(cond, msg) \ + if (!(cond)) \ + return false; diff --git a/src/output_processing/include/output_processing/output_handlers.hpp b/src/output_processing/include/output_processing/output_handlers.hpp new file mode 100644 index 000000000..e6717d338 --- /dev/null +++ b/src/output_processing/include/output_processing/output_handlers.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include +#include +#include + + +bool ClassificationTask(const std::map>>& output_tensors, + const size_t number_top, const std::string& labels); \ No newline at end of file diff --git a/src/output_processing/include/output_processing/utils.hpp b/src/output_processing/include/output_processing/utils.hpp new file mode 100644 index 000000000..307c33002 --- /dev/null +++ b/src/output_processing/include/output_processing/utils.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include +#include + + +std::vector read_labels(const std::string& label_path); + +template +std::vector argsort(const std::vector &array) { + std::vector indices(array.size()); + std::iota(indices.begin(), indices.end(), 0); + std::sort(indices.begin(), indices.end(), + [&array](int left, int right) -> bool { + return array[left] < array[right]; + }); + + return indices; +} \ No newline at end of file diff --git a/src/output_processing/output_processing.cpp b/src/output_processing/output_processing.cpp new file mode 100644 index 000000000..980f7d355 --- /dev/null +++ b/src/output_processing/output_processing.cpp @@ -0,0 +1,7 @@ +#include + +#include "wrappers.hpp" + +PYBIND11_MODULE(output_processing, m) { + m.def("ClassificationTask", &ClassificationTaskPy); +}; \ No newline at end of file diff --git a/src/output_processing/src/output_handlers.cpp b/src/output_processing/src/output_handlers.cpp new file mode 100644 index 000000000..b180411c9 --- /dev/null +++ b/src/output_processing/src/output_handlers.cpp @@ -0,0 +1,34 @@ +#include "output_processing/output_handlers.hpp" + +#include "output_processing/exception_handler.hpp" +#include "output_processing/utils.hpp" + +#include +#include + + +bool ClassificationTask(const std::map>>& output_tensors, + const size_t number_top, const std::string& label_file) { + DLB_ASSERT(output_tensors.size() == 1) + + const auto result_tensor = *output_tensors.cbegin(); + const auto layer_name = result_tensor.first; + const auto data = result_tensor.second; + const auto labels = read_labels(label_file); + const auto batch = data.size(); + + std::cout << "[ INFO ] Top " + std::to_string(number_top) + " results:\n"; + + for (size_t i = 0; i < batch; ++i) { + const auto batch_result = data[i]; + const auto top_idxs = argsort(batch_result); + + std::cout << "[ INFO ] Result for image " + std::to_string(i + 1) + ":\n"; + for (size_t idx = 0; idx < number_top; ++idx) { + std::cout.precision(2); + const auto sorted_index = top_idxs[idx]; + std::cout << std::setw(10) << batch_result[sorted_index] << std::setw(5) << labels[sorted_index] << "\n"; + } + } + return true; +} \ No newline at end of file diff --git a/src/output_processing/src/utils.cpp b/src/output_processing/src/utils.cpp new file mode 100644 index 000000000..14cdba9e1 --- /dev/null +++ b/src/output_processing/src/utils.cpp @@ -0,0 +1,25 @@ +#include "output_processing/utils.hpp" + +#include +#include + + +std::vector read_labels(const std::string& label_path) { + std::vector labels; + + std::filesystem::path path = label_path; + std::ifstream in(path); + if (in.is_open()) { + std::string label; + while (std::getline(in, label)) { + labels.push_back(label); + } + } + in.close(); + if (path.extension() == ".json") { + // Remove parenthless + labels.pop_back(); + labels.erase(labels.begin()); + } + return labels; +} \ No newline at end of file diff --git a/src/output_processing/thirdparty/pybind11 b/src/output_processing/thirdparty/pybind11 new file mode 160000 index 000000000..2b2e4ca4a --- /dev/null +++ b/src/output_processing/thirdparty/pybind11 @@ -0,0 +1 @@ +Subproject commit 2b2e4ca4a3fe162bf9c4c95d1621dadab071df86 diff --git a/src/output_processing/wrappers.hpp b/src/output_processing/wrappers.hpp new file mode 100644 index 000000000..e57dc80ef --- /dev/null +++ b/src/output_processing/wrappers.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +#include "output_processing/output_handlers.hpp" +#include "output_processing/exception_handler.hpp" + +#include +#include +#include + + +namespace py = pybind11; + + +void ClassificationTaskPy(const py::dict& map, const size_t number_top, + const std::string& label_file) { + std::map>> tensors; + for (const auto& it : map) { + const std::string& layer_name = py::cast(it.first); + const py::array& py_tensor = py::cast(it.second); + } +} \ No newline at end of file