diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 31adbd5..c08c9d6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,9 @@ jobs: - name: Install dependencies run: | sudo apt-get install -y cmake ninja-build ccache scons + sudo apt-get install python3-dev libprotobuf-dev protobuf-compiler + python -m pip install --upgrade pip + python -m pip install -r requirements.txt - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: @@ -38,6 +41,9 @@ jobs: - name: Install dependencies run: | sudo apt-get install -y cmake ninja-build ccache scons + sudo apt-get install python3-dev libprotobuf-dev protobuf-compiler + python -m pip install --upgrade pip + python -m pip install -r requirements.txt - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: @@ -59,7 +65,20 @@ jobs: submodules: recursive - name: Install dependencies run: | - brew install ninja scons + brew install ninja scons + + + + + + + + + + + + python -m pip install --upgrade pip + python -m pip install -r requirements.txt - name: ccache uses: hendrikmuhs/ccache-action@v1.2 with: @@ -82,6 +101,9 @@ jobs: - name: Install dependencies run: | sudo apt-get install -y cmake ninja-build ccache gcovr lcov scons + sudo apt-get install python3-dev libprotobuf-dev protobuf-compiler + python -m pip install --upgrade pip + python -m pip install -r requirements.txt - uses: actions/checkout@v4 with: submodules: true diff --git a/IR/IR.cpp b/IR/IR.cpp new file mode 100644 index 0000000..bf93ac9 --- /dev/null +++ b/IR/IR.cpp @@ -0,0 +1,46 @@ +#include "IR.h" + +IR::IR(std::string filename, Model model) : _graph() { + _fileName = filename; + _model = model; + switch (_model) { + case Model::ONNX: + _modelParser = new ONNX_ModelParser(_fileName); + break; + + case Model::OPENCV: + _modelParser = new OPENCV_ModelParser(_fileName); + break; + + default: + break; + } + + _graph = _modelParser->Parse(); +} + +const bool IR::operator==(const IR& _other) const { + std::unordered_map first_model_map; + std::unordered_map second_model_map; + + std::hash hashMaker; + + std::vector vec = _graph.getLayersTypeVector(); + for (auto it : _graph) { + first_model_map.insert(it.getId(), std::to_string(hashMaker(it.vec))); + } + + for (auto it : _other._graph) { + second_model_map.insert(it.getId(), std::to_string(hashMaker(it.vec))); + } + + if (first_model_map == second_model_map) { + return true; + } + return false; +} + +IR::~IR() { + delete _modelParser; + _modelParser = nullptr; +} \ No newline at end of file diff --git a/IR/IR.h b/IR/IR.h new file mode 100644 index 0000000..30f9d66 --- /dev/null +++ b/IR/IR.h @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include "graph.h" +#include "map" + +class AnyLayer : protected Layer { + private: + std::string _name; + std::map _attribute; + std::vector weights; + std::vector bias; + + public: + AnyLayer(); + ~AnyLayer() = default; + + void addNeighbor(Layer* neighbor); + void removeNeighbor(Layer* neighbor); + std::list neighbors_; +}; + +enum Model { ONNX, PYTORCH, OPENCV }; + +class ModelParser { + protected: + std::string _fileName; + + public: + explicit ModelParser(std::string filename) : _fileName(std::move(filename)) {} + virtual ~ModelParser() = default; + virtual Network Parse() = 0; +}; + +class ONNX_ModelParser : public ModelParser { + public: + explicit ONNX_ModelParser(std::string filename) + : ModelParser(std::move(filename)) {} + Network Parse() override; +}; + +class OPENCV_ModelParser : public ModelParser { + public: + explicit OPENCV_ModelParser(std::string filename) + : ModelParser(std::move(filename)) {} + Network Parse() override; +}; + +class IR { + private: + std::string _fileName; + Network _graph; + Model _model; + ModelParser* _modelParser; + + public: + IR(std::string filename, Model model); + + const bool operator==(const IR& _other) const; + + // void ChangeModelType(Model model){ + // _model = model; + // } + + // void ChangeFile(std::string filename){ + // _fileName = filename; + // } + + ~IR(); +}; diff --git a/README.md b/README.md index 0553cc6..9429ee1 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ If your OpenCV build does not use CUDA/cuDNN you can remove that import call and run the example on CPU. ## How to build ONNX library on Linux(Ubuntu) - + 1. Install necessary tools: ``` sudo apt-get install -y python3-pip diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index a5c4dce..4845528 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(frontend) add_subdirectory(example) diff --git a/app/frontend/CMakeLists.txt b/app/frontend/CMakeLists.txt new file mode 100644 index 0000000..4cf6228 --- /dev/null +++ b/app/frontend/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.10) +project(ModelParser) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Protobuf REQUIRED) + +set(ONNX_GENERATED_DIR "${CMAKE_SOURCE_DIR}/generated") + +set(ONNX_PROTO_SRCS + "${ONNX_GENERATED_DIR}/onnx.pb.cc" +) + +set(ONNX_GENERATED_HEADER + "${ONNX_GENERATED_DIR}/onnx.pb.h" +) + +set(SRC_FILES + main.cpp + ${ONNX_PROTO_SRCS} +) + +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/generated/onnx.pb.h PROPERTIES GENERATED TRUE) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/generated/onnx.pb.cc PROPERTIES GENERATED TRUE) +set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/generated/yolo11x.onnx PROPERTIES GENERATED TRUE) + +file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/generated) + +set(YOLO_SRC "${CMAKE_SOURCE_DIR}/generated/yolo11x.onnx") +set(YOLO_DST "${CMAKE_CURRENT_BINARY_DIR}/generated/yolo11x.onnx") + +if(EXISTS "${YOLO_SRC}") + configure_file(${YOLO_SRC} ${YOLO_DST} COPYONLY) +else() + file(WRITE "${YOLO_DST}" "") +endif() + +add_executable(ModelParser ${SRC_FILES}) + +target_include_directories(ModelParser PRIVATE + ${ONNX_GENERATED_DIR} + ${Protobuf_INCLUDE_DIRS} +) + +target_link_libraries(ModelParser + ${Protobuf_LIBRARIES} + ${ONNX_GENERATED_HEADER} +) diff --git a/app/frontend/GetModel.sh b/app/frontend/GetModel.sh new file mode 100644 index 0000000..546243a --- /dev/null +++ b/app/frontend/GetModel.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir generated +protoc --proto_path=../../3rdparty/onnx/onnx --cpp_out=./generated onnx.proto +yolo export model=yolo11x.pt format=onnx save_dir=./generated + + diff --git a/app/frontend/README.md b/app/frontend/README.md new file mode 100644 index 0000000..b41db91 --- /dev/null +++ b/app/frontend/README.md @@ -0,0 +1,19 @@ +## __How to run yolov11x model parser__ + +1. Build the project. + +2. Get a network model using Ultralytics CLI + +- Give "executable mode" to the script GetModel.sh + ``` + chmod +x GetModel.sh + ``` +- Run script + ``` + bash GetModel.sh + ``` + +3. Run the project + ``` + ./ModelParser + ``` diff --git a/app/frontend/main.cpp b/app/frontend/main.cpp new file mode 100644 index 0000000..71736c2 --- /dev/null +++ b/app/frontend/main.cpp @@ -0,0 +1,35 @@ +#include +#include +#include +#include + +#include "onnx.pb.h" + +int main() { + std::ifstream model_file("generated/yolo11x.onnx", std::ios::binary); + + if (!model_file.is_open()) { + std::cerr << "Failed to open model" << std::endl; + return 1; + } + + onnx::ModelProto model; + if (!model.ParseFromIstream(&model_file)) { + std::cerr << "Model parsing error" << std::endl; + return 1; + } + model_file.close(); + + std::vector layer; + + for (int i = 0; i < model.graph().node_size(); ++i) { + const onnx::NodeProto& node = model.graph().node(i); + layer.emplace_back(node.op_type()); + } + + for (auto it : layer) { + std::cout << it << std::endl; + } + + return 0; +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..33bf75c --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +ultralytics>=8.3.32