Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

40 qnn direct #43

Merged
merged 78 commits into from
Jul 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
7931a7e
Remove Android requirement for qnn dependency
ciaranbor Jul 7, 2024
4fb5ebb
Link qnn libraries privately
ciaranbor Jul 7, 2024
cb00fae
Add STATUS return for load model methods
ciaranbor Jul 7, 2024
b36b821
Update tflite loadModel methods to return STATUS
ciaranbor Jul 7, 2024
2a4c420
Reflect change from qnn::tfliteDelegate qnn::tflite target
ciaranbor Jul 7, 2024
2889c6c
Reflect new QNN include path
ciaranbor Jul 7, 2024
8ac31a6
Move imagenet_labels to common model directory
ciaranbor Jul 7, 2024
f91f18c
Modify clang-tidy formatting
ciaranbor Jul 10, 2024
8444448
Add qnn::Backend class to handle interacting with QNN shared libraries
ciaranbor Jul 11, 2024
1240aa8
Implement loadBackend method
ciaranbor Jul 11, 2024
aa03157
Add method to verify that the correct QNN backend is loaded
ciaranbor Jul 11, 2024
f6ab243
Add method to load system library
ciaranbor Jul 12, 2024
6be902d
Add method to initialize backend
ciaranbor Jul 12, 2024
84c63d8
Add method to create device
ciaranbor Jul 12, 2024
536eeb1
Add method to create context
ciaranbor Jul 12, 2024
55f557d
Add constructor to create backend objects
ciaranbor Jul 12, 2024
e1bdac6
Add destructor to destroy backend objects
ciaranbor Jul 12, 2024
beddcdb
Tweak clang-tidy formatting rules
ciaranbor Jul 12, 2024
6597555
Add QNN logging support
ciaranbor Jul 13, 2024
9739ce3
Add templated Config class to handle applying custom config options
ciaranbor Jul 13, 2024
c13df3d
Add Backend methods to access internal QNN objects
ciaranbor Jul 13, 2024
781fcf5
Fix QNN teardown order in Backend constructor
ciaranbor Jul 13, 2024
5132efa
Remove qnn::backend namespace
ciaranbor Jul 13, 2024
405fbc9
Link to qnn::qnn if NPU is enabled
ciaranbor Jul 13, 2024
0e1f68b
Reflect change to QNN tflite target name
ciaranbor Jul 13, 2024
bed94e0
Make EDGERUNNER_QNN compile definition public
ciaranbor Jul 13, 2024
c1ce24b
Add QNN Tensor class interface
ciaranbor Jul 13, 2024
a810197
Implement qnn::TensorImpl construction from a Qnn_Tensor_t wrapper
ciaranbor Jul 13, 2024
5ac7c2d
Implement qnn::TensorImpl::getName()
ciaranbor Jul 13, 2024
7f8f94b
Implement qnn::TensorImpl::getType()
ciaranbor Jul 13, 2024
a6dd140
Implement qnn::TensorImpl::getDimensions()
ciaranbor Jul 13, 2024
ee26391
Implement qnn::TensorImpl::getSize()
ciaranbor Jul 13, 2024
258ace1
Implement qnn::TensorImpl::getDataPtr()
ciaranbor Jul 13, 2024
d9adac3
Implement qnn::TensorImpl::getNumBytes()
ciaranbor Jul 13, 2024
743fece
Add qnn::ModelImpl class interface
ciaranbor Jul 13, 2024
b0dbadb
Add Backend to ModelImpl
ciaranbor Jul 13, 2024
9a93d3b
Add qnn helper functions and types
ciaranbor Jul 13, 2024
0ac6576
Add qnn graph handle and info objects
ciaranbor Jul 13, 2024
7e8dc1a
Add method to load a shared library qnn model
ciaranbor Jul 13, 2024
1ed8780
Fail on cached binary load for now
ciaranbor Jul 13, 2024
d8dc577
Implement applyDelegate - fail if not NPU
ciaranbor Jul 13, 2024
9614eb4
Add composeGraphs method, using function handle loaded from qnn share…
ciaranbor Jul 13, 2024
c1156c7
Add method to finalize QNN graph
ciaranbor Jul 13, 2024
1ffd27e
Add method to set graph config options, currently hardcoded to set pr…
ciaranbor Jul 13, 2024
52e9d99
Allocate input and output tensors by querying graph info
ciaranbor Jul 13, 2024
17556c2
Implement qnn graph execution
ciaranbor Jul 13, 2024
382b25c
Implement qnn::ModelImpl constructor, check if model is .so or .bin a…
ciaranbor Jul 13, 2024
08eabe1
Deallocate graph and close shared library upon destruction
ciaranbor Jul 13, 2024
39e2501
Delegate to QNN backend for .so model files
ciaranbor Jul 13, 2024
b770283
Return STATUS from internal tflite methods
ciaranbor Jul 13, 2024
fb340af
Models set creation status during construction
ciaranbor Jul 13, 2024
29b2887
Use std::vector for underlying Qnn_Tensor_t data
ciaranbor Jul 13, 2024
677d834
Use span for querying qnn tensor dimensions
ciaranbor Jul 13, 2024
8711a1b
Reformatting
ciaranbor Jul 13, 2024
2ee46e7
Fix qnn tensor getDimensions
ciaranbor Jul 13, 2024
e797ae2
createModel returns nullptr if model creation fails
ciaranbor Jul 13, 2024
08d2a7b
Fix Config for multiple config options
ciaranbor Jul 13, 2024
a3891a3
Set graph optimization level to max
ciaranbor Jul 13, 2024
ab0059c
Set power config for higher performance
ciaranbor Jul 13, 2024
e3ea866
Move qnn::ModelImpl constructors to source file
ciaranbor Jul 13, 2024
f478abe
Use std::variant to wrap accessing different Qnn_Tensor versions
ciaranbor Jul 13, 2024
a8c5495
Use std::variant to access Qnn tensor memory
ciaranbor Jul 13, 2024
cfac0a7
Refactor power config setting
ciaranbor Jul 13, 2024
f14ecd3
Use dedicated qnn::ModelImpl member for storing graph (assuming singl…
ciaranbor Jul 13, 2024
7fab094
Move qnn::ModelImpl desctructor to source file
ciaranbor Jul 13, 2024
b8609ae
Move tflite::ModelImpl constructors to source file
ciaranbor Jul 13, 2024
56de348
Fix spelling
ciaranbor Jul 14, 2024
67d2b0e
Update to clang-format-15 for Lint CI job
ciaranbor Jul 14, 2024
b9849ef
Hide creating QNN model behind preprocessor definition
ciaranbor Jul 14, 2024
73d9485
Complete qnn::ModelImpl documentation
ciaranbor Jul 14, 2024
db44f92
Document config.h
ciaranbor Jul 14, 2024
b7d9b16
Standardize file extensions
ciaranbor Jul 14, 2024
438526a
Document backend.hpp
ciaranbor Jul 14, 2024
3983d98
Move invalid model tests to dedicated test case
ciaranbor Jul 14, 2024
3358ff1
Test more invalid model variants
ciaranbor Jul 14, 2024
96f0e5c
Improve TFLite model creation error handling
ciaranbor Jul 14, 2024
7ca6588
Resolve std::visit argument shadowing
ciaranbor Jul 14, 2024
a7c8928
Add QNN to supported runtimes list
ciaranbor Jul 14, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,16 @@ CheckOptions:
value: 'camelBack'
- key: 'readability-identifier-naming.ClassMemberCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ClassMemberPrefix'
value: 'm_'
- key: 'readability-identifier-naming.ClassMethodCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ConstantCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ConstantMemberCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ConstantMemberPrefix'
value: 'm_'
- key: 'readability-identifier-naming.ConstantParameterCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ConstantPointerParameterCase'
Expand All @@ -69,11 +73,11 @@ CheckOptions:
- key: 'readability-identifier-naming.ConstexprMethodCase'
value: 'camelBack'
- key: 'readability-identifier-naming.ConstexprVariableCase'
value: 'camelBack'
value: 'CamelCase'
- key: 'readability-identifier-naming.EnumCase'
value: 'CamelCase'
- key: 'readability-identifier-naming.EnumConstantCase'
value: 'CamelCase'
value: 'UPPER_CASE'
- key: 'readability-identifier-naming.FunctionCase'
value: 'camelBack'
- key: 'readability-identifier-naming.GlobalConstantCase'
Expand Down Expand Up @@ -133,15 +137,15 @@ CheckOptions:
- key: 'readability-identifier-naming.StaticVariableCase'
value: 'camelBack'
- key: 'readability-identifier-naming.StructCase'
value: 'camelBack'
value: 'CamelCase'
- key: 'readability-identifier-naming.TemplateParameterCase'
value: 'CamelCase'
- key: 'readability-identifier-naming.TemplateTemplateParameterCase'
value: 'CamelCase'
- key: 'readability-identifier-naming.TypeAliasCase'
value: 'camelBack'
value: 'CamelCase'
- key: 'readability-identifier-naming.TypedefCase'
value: 'camelBack'
value: 'CamelCase'
- key: 'readability-identifier-naming.TypeTemplateParameterCase'
value: 'CamelCase'
- key: 'readability-identifier-naming.UnionCase'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
run: pip3 install codespell

- name: Lint
run: cmake -D FORMAT_COMMAND=clang-format-14 -P cmake/lint.cmake
run: cmake -D FORMAT_COMMAND=clang-format-15 -P cmake/lint.cmake

- name: Spell check
if: always()
Expand Down
30 changes: 20 additions & 10 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,29 @@ target_link_libraries(edgerunner_edgerunner PUBLIC nonstd::span-lite)
find_package(tensorflowlite REQUIRED)
target_link_libraries(edgerunner_edgerunner PRIVATE tensorflow::tensorflowlite)

if(ANDROID AND edgerunner_ENABLE_NPU)
find_package(qnn REQUIRED COMPONENTS tfliteDelegate)
target_link_libraries(edgerunner_edgerunner PUBLIC qnn::tfliteDelegate)

target_compile_definitions(edgerunner_edgerunner PUBLIC EDGERUNNER_QNN)
if(edgerunner_ENABLE_GPU)
target_compile_definitions(edgerunner_edgerunner PUBLIC EDGERUNNER_GPU)
endif()

file(COPY "${CMAKE_BINARY_DIR}/../runtimeLibs/"
DESTINATION ${CMAKE_BINARY_DIR}
if(edgerunner_ENABLE_NPU)
target_sources(
edgerunner_edgerunner
PRIVATE source/qnn/model.cpp source/qnn/tensor.cpp
source/qnn/backend.cpp
)
endif()

if(edgerunner_ENABLE_GPU)
target_compile_definitions(edgerunner_edgerunner PUBLIC EDGERUNNER_GPU)
find_package(qnn REQUIRED)

if(ANDROID)
target_link_libraries(edgerunner_edgerunner PRIVATE qnn::tflite)
target_compile_definitions(edgerunner_edgerunner PUBLIC EDGERUNNER_QNN)

file(COPY "${CMAKE_BINARY_DIR}/../runtimeLibs/"
DESTINATION ${CMAKE_BINARY_DIR}
)
else()
target_link_libraries(edgerunner_edgerunner PRIVATE qnn::qnn)
endif()
endif()

# ---- Install rules ----
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Please request additional features through Github issues or on our [Discord](htt

| TFLite | CoreML | Onnx | QNN | OpenVino | Ryzen AI | NeuroPilot |
|:------:|:------:|:----:|:---:|:--------:|:--------:|:----------:|
| ✅ | ⏳ | ⏳ | | ⏳ | ⏳ | ⏳ |
| ✅ | ⏳ | ⏳ | | ⏳ | ⏳ | ⏳ |

### Chip Vendor

Expand Down
6 changes: 3 additions & 3 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def requirements(self):
if self.options.examples:
self.requires("opencv/4.9.0")

if self.settings.os == "Android" and self.options.with_npu:
if self.options.with_npu:
self.requires("qnn/2.23.0.24.06.24")

def build_requirements(self):
Expand Down Expand Up @@ -92,12 +92,12 @@ def generate(self):

toolchain.generate()

if self.settings.os == "Android" and self.options.with_npu:
if self.options.with_npu:
qnn = self.dependencies["qnn"]
copy(
self,
"*.so",
qnn.cpp_info.components["tfliteDelegate"].libdirs[0],
qnn.cpp_info.components["tflite"].libdirs[0],
os.path.join(self.source_folder, "build", "runtimeLibs"),
)
copy(
Expand Down
4 changes: 2 additions & 2 deletions example/imageClassifier.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <fstream>
#include <limits>
#include <numeric>
#include <ratio>
#include <string>

#include <fmt/core.h>
Expand All @@ -19,7 +20,6 @@ class ImageClassifier {
public:
ImageClassifier(const std::filesystem::path& modelPath,
const std::filesystem::path& labelListPath);

auto loadImage(const std::filesystem::path& imagePath) -> edge::STATUS;

auto setDelegate(edge::DELEGATE delegate) -> edge::STATUS;
Expand Down Expand Up @@ -76,7 +76,7 @@ class ImageClassifier {
};

inline ImageClassifier::ImageClassifier(
const std::filesystem::path& modelPath,
const std::filesystem::path& modelPath, /* NOLINT */
const std::filesystem::path& labelListPath)
: m_model(edge::createModel(modelPath))
, m_labelList(loadLabelList(labelListPath)) {}
Expand Down
6 changes: 3 additions & 3 deletions example/mobilenet_v3_small.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ auto main() -> int {
const std::filesystem::path modelPath {
"models/tflite/mobilenet_v3_small.tflite"};
const std::filesystem::path labelListPath {
"models/tflite/imagenet_labels.txt"};
"models/common/imagenet_labels.txt"};

ImageClassifier imageClassifier(modelPath, labelListPath);

#ifdef EDGERUNNER_QNN
#if defined(EDGERUNNER_QNN)
imageClassifier.setDelegate(edge::DELEGATE::NPU);
#elif EDGERUNNER_GPU
#elif defined(EDGERUNNER_GPU)
imageClassifier.setDelegate(edge::DELEGATE::GPU);
#endif

Expand Down
43 changes: 41 additions & 2 deletions include/edgerunner/model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,26 @@ class EDGERUNNER_EXPORT Model {
/**
* @brief Pure virtual function to load a model from a file path.
*
* This function is a pure virtual function that must be implemented by any
* derived classes. It is used to load a model from a file path.
*
* @param modelPath The path to the model file
* @return STATUS The status of the model loading operation
*/
virtual void loadModel(const std::filesystem::path& modelPath) = 0;
virtual auto loadModel(const std::filesystem::path& modelPath)
-> STATUS = 0;

/**
* @brief Pure virtual function to load a model from a file buffer.
*
* This function is a pure virtual function that must be implemented by any
* derived classes. It is used to load a model from a file buffer.
*
* @param modelBuffer The buffer containing the model
* @return STATUS The status of the model loading operation
*/
virtual void loadModel(const nonstd::span<uint8_t>& modelBuffer) = 0;
virtual auto loadModel(const nonstd::span<uint8_t>& modelBuffer)
-> STATUS = 0;

/**
* @brief Get the number of input tensors in the model.
Expand Down Expand Up @@ -168,14 +178,40 @@ class EDGERUNNER_EXPORT Model {
*/
auto name() const -> const std::string& { return m_name; }

/**
* @brief Get the status of model creation.
*
* Verify that the model was created successfully
*
* @return The status of model creation
*/
auto getCreationStatus() const -> STATUS { return m_creationStatus; }

protected:
/**
* @brief Set the delegate for model execution.
*
* This method is used by derivatives to allow users to query the currently
* set delegate
*
* @param delegate The delegate to set
*/
void setDelegate(const DELEGATE& delegate) { m_delegate = delegate; }

/**
* @brief Set the status of model creation.
*
* This method is used by derivatives to allow querying of model creation
* status
*
* @param status The status to set
*/
void setCreationStatus(const STATUS& status) {
if (m_creationStatus == STATUS::SUCCESS) {
m_creationStatus = status;
}
}

private:
EDGERUNNER_SUPPRESS_C4251
std::string m_name; /**< Name of the model */
Expand All @@ -191,6 +227,9 @@ class EDGERUNNER_EXPORT Model {
EDGERUNNER_SUPPRESS_C4251
DELEGATE m_delegate =
DELEGATE::CPU; /**< Delegate used for model execution */

EDGERUNNER_SUPPRESS_C4251
STATUS m_creationStatus = STATUS::SUCCESS; /**< Status of model creation */
};

inline auto Model::getInput(size_t index) const -> std::shared_ptr<Tensor> {
Expand Down
139 changes: 139 additions & 0 deletions include/edgerunner/qnn/backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/**
* @file Backend.h
* @brief Definition of the Backend class for handling QNN backends.
*
* This class represents a backend for handling interfacing with QNN backend
* libraries. It provides functionality for loading the backend, creating a
* device, initializing the backend, and managing the context for QNN
* operations.
*
* The Backend class is currently restricted to NPU inference support.
*/

#pragma once

#include <unordered_map>

#include <HTP/QnnHtpDevice.h>
#include <QnnCommon.h>
#include <QnnInterface.h>
#include <QnnTypes.h>
#include <System/QnnSystemInterface.h>
#include <fmt/core.h>

/* TODO: move STATUS to dedicated header */
#include "edgerunner/model.hpp"

namespace edge::qnn {

/**
* @class Backend
* @brief Class for handling QNN backends.
*/
class Backend {
public:
/**
* @brief Constructor for the Backend class.
* @param delegate The delegate type for the backend (CPU, GPU, NPU).
*/
explicit Backend(DELEGATE delegate);

Backend(const Backend&) = default;
Backend(Backend&&) = delete;
auto operator=(const Backend&) -> Backend& = delete;
auto operator=(Backend&&) -> Backend& = delete;

/**
* @brief Destructor for the Backend class.
*/
~Backend();

/**
* @brief Get the backend handle.
* @return Reference to the backend handle.
*/
auto getHandle() -> auto& { return m_backendHandle; }

/**
* @brief Get the context for the backend.
* @return Reference to the backend context.
*/
auto getContext() -> auto& { return m_context; }

/**
* @brief Get the QNN interface.
* @return Reference to the QNN interface.
*/
auto getInterface() -> auto& { return m_qnnInterface; }

/**
* @brief Get the delegate type for the backend.
* @return The delegate type.
*/
auto getDelegate() { return m_delegate; }

/**
* @brief Static callback function for logging.
* @param fmtStr The format string for the log message.
* @param level The log level.
* @param timestamp The timestamp of the log message.
* @param argp Additional arguments for the log message.
*/
static void logCallback(const char* fmtStr,
QnnLog_Level_t level,
uint64_t timestamp,
va_list argp);

private:
auto loadBackend() -> STATUS;

auto createLogger() -> STATUS;

auto initializeBackend() -> STATUS;

auto loadSystemLibrary() -> STATUS;

auto createDevice() -> STATUS;

auto createContext() -> STATUS;

auto setPowerConfig() -> STATUS;

auto destroyPowerConfig() const -> STATUS;

auto loadContextFromBinary() -> STATUS;

auto validateBackendId(uint32_t backendId) const -> STATUS;

void* m_backendLibHandle {};
void* m_systemLibHandle {};

Qnn_BackendHandle_t m_backendHandle {};
QnnBackend_Config_t** m_backendConfig {};

Qnn_DeviceHandle_t m_deviceHandle {};

Qnn_ContextHandle_t m_context {};

Qnn_LogHandle_t m_logHandle {};

uint32_t m_powerConfigId {};

QnnHtpDevice_PerfInfrastructure_t m_devicePerfInfrastructure {};

QNN_INTERFACE_VER_TYPE m_qnnInterface = QNN_INTERFACE_VER_TYPE_INIT;
QNN_SYSTEM_INTERFACE_VER_TYPE m_qnnSystemInterface =
QNN_SYSTEM_INTERFACE_VER_TYPE_INIT;

DELEGATE m_delegate;

std::unordered_map<DELEGATE, std::string> m_backendLibrariesByDelegate {
{DELEGATE::CPU, "libQnnCpu.so"},
{DELEGATE::GPU, "libQnnGpu.so"},
{DELEGATE::NPU, "libQnnHtp.so"}};

uint32_t m_deviceId {};
QnnHtpDevice_Arch_t m_htpArch {};
};

} // namespace edge::qnn
Loading