Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 40 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,20 @@ find_package(onnxruntime REQUIRED)
find_package(Eigen3 REQUIRED)
message("OpenCV_LIBS: ${OpenCV_LIBS} ${OPENCV_core_FOUND} ${OPENCV_WORLD_FOUND}")

# ONNX Runtime flattens the headers of every enabled execution provider into
# <onnxruntime/>, so <onnxruntime/webgpu_provider_factory.h> exists exactly when
# that ONNX Runtime was built with the WebGPU EP (the same signal the Maa
# side uses for DirectML/CoreML). FastDeploy always compiles the WebGPU device
# path and falls back to Device::CPU at runtime when the EP is unavailable, so
# this reports what the linked ONNX Runtime can actually do -- pick the ONNX
# Runtime accordingly if you need the device.
if(EXISTS "${onnxruntime_INCLUDE_DIR}/webgpu_provider_factory.h")
set(WITH_WEBGPU ON)
else()
set(WITH_WEBGPU OFF)
endif()
message(STATUS "WITH_WEBGPU: ${WITH_WEBGPU} (onnxruntime_INCLUDE_DIR=${onnxruntime_INCLUDE_DIR})")

option(WITH_CUDA "Whether WITH_CUDA=ON, will enable onnxruntime-gpu/paddle-inference-gpu" OFF)
option(PRINT_INFO "Print more debug info while running" OFF)

Expand Down Expand Up @@ -117,7 +131,11 @@ set_target_properties(

target_include_directories(fastdeploy_ppocr INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> # for build
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDE}> # for install
# Headers are installed to <prefix>/include (see the install() below).
# CMAKE_INSTALL_INCLUDE is not defined in this project, so spell the
# relative path out: an empty INSTALL_INTERFACE leaves the imported target
# without any include directory for consumers.
$<INSTALL_INTERFACE:include> # for install
)

target_link_libraries(fastdeploy_ppocr PUBLIC ${OpenCV_LIBS} PRIVATE onnxruntime::onnxruntime)
Expand All @@ -129,7 +147,27 @@ if(ANDROID)
endif()

install(TARGETS fastdeploy_ppocr EXPORT fastdeploy_ppocrConfig)
install(EXPORT fastdeploy_ppocrConfig DESTINATION share/fastdeploy_ppocr)
include(CMakePackageConfigHelpers)
install(EXPORT fastdeploy_ppocrConfig
DESTINATION share/fastdeploy_ppocr
FILE fastdeploy_ppocrTargets.cmake)
# A static build leaks $<LINK_ONLY:onnxruntime::onnxruntime> into the exported
# interface, so the package config has to help consumers materialize that
# target; ship the Find module it needs.
get_target_property(FASTDEPLOY_PPOCR_LIBRARY_TYPE fastdeploy_ppocr TYPE)
if(FASTDEPLOY_PPOCR_LIBRARY_TYPE STREQUAL "STATIC_LIBRARY")
set(FASTDEPLOY_PPOCR_STATIC ON)
else()
set(FASTDEPLOY_PPOCR_STATIC OFF)
endif()
install(FILES cmake/Findonnxruntime.cmake
DESTINATION share/fastdeploy_ppocr/cmake)
configure_package_config_file(
cmake/fastdeploy_ppocrConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/fastdeploy_ppocrConfig.cmake
INSTALL_DESTINATION share/fastdeploy_ppocr)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/fastdeploy_ppocrConfig.cmake
DESTINATION share/fastdeploy_ppocr)
install(
DIRECTORY ${PROJECT_SOURCE_DIR}/fastdeploy
DESTINATION include
Expand Down
27 changes: 27 additions & 0 deletions cmake/fastdeploy_ppocrConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)

# fastdeploy_ppocr's public headers need OpenCV and the exported target links
# opencv_core/opencv_imgproc, so those targets have to exist in the consumer.
find_dependency(OpenCV COMPONENTS core imgproc)

# A static fastdeploy_ppocr carries $<LINK_ONLY:onnxruntime::onnxruntime> in its
# interface, while a shared one does not. ONNX Runtime does not always install a
# CMake package discoverable as "onnxruntime", so look through the Find module
# shipped next to this file first.
set(fastdeploy_ppocr_STATIC @FASTDEPLOY_PPOCR_STATIC@)
if(fastdeploy_ppocr_STATIC AND NOT TARGET onnxruntime::onnxruntime)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_dependency(onnxruntime)
endif()

# Whether the ONNX Runtime this FastDeploy was built against ships the WebGPU
# EP. The device path itself is always compiled in and still falls back to
# Device::CPU at runtime if the EP is missing, so treat this as a hint for
# choosing devices, not as a guarantee.
set(fastdeploy_ppocr_WITH_WEBGPU @WITH_WEBGPU@)

include("${CMAKE_CURRENT_LIST_DIR}/fastdeploy_ppocrTargets.cmake")

check_required_components(fastdeploy_ppocr)
4 changes: 4 additions & 0 deletions fastdeploy/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
#define WITH_COREML
#endif

#ifndef WITH_WEBGPU
#define WITH_WEBGPU
#endif

#ifndef ENABLE_TRT_BACKEND
/* #undef ENABLE_TRT_BACKEND */
#endif
Expand Down
4 changes: 4 additions & 0 deletions fastdeploy/core/config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@
#cmakedefine WITH_COREML
#endif

#ifndef WITH_WEBGPU
#cmakedefine WITH_WEBGPU
#endif

#ifndef ENABLE_TRT_BACKEND
#cmakedefine ENABLE_TRT_BACKEND
#endif
Expand Down
36 changes: 35 additions & 1 deletion fastdeploy/fastdeploy_model.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ bool FastDeployModel::InitRuntimeWithSpecifiedBackend() {
bool use_ascend = (runtime_option.device == Device::ASCEND);
bool use_directml = (runtime_option.device == Device::DIRECTML);
bool use_coreml = (runtime_option.device == Device::COREML);
bool use_webgpu = (runtime_option.device == Device::WEBGPU);
bool use_kunlunxin = (runtime_option.device == Device::KUNLUNXIN);

if (use_cuda) {
Expand Down Expand Up @@ -141,6 +142,13 @@ bool FastDeployModel::InitRuntimeWithSpecifiedBackend() {
<< runtime_option.backend << " is not supported." << std::endl;
return false;
}
} else if (use_webgpu) {
if (!IsSupported(valid_webgpu_backends, runtime_option.backend)) {
FDERROR << "The valid webgpu backends of model " << ModelName()
<< " are " << Str(valid_webgpu_backends) << ", "
<< runtime_option.backend << " is not supported." << std::endl;
return false;
}
} else if (use_kunlunxin) {
if (!IsSupported(valid_kunlunxin_backends, runtime_option.backend)) {
FDERROR << "The valid kunlunxin backends of model " << ModelName()
Expand Down Expand Up @@ -195,6 +203,8 @@ bool FastDeployModel::InitRuntimeWithSpecifiedDevice() {
return CreateDirectMLBackend();
} else if (runtime_option.device == Device::COREML) {
return CreateCoreMLBackend();
} else if (runtime_option.device == Device::WEBGPU) {
return CreateWebGPUBackend();
} else if (runtime_option.device == Device::KUNLUNXIN) {
return CreateKunlunXinBackend();
} else if (runtime_option.device == Device::SOPHGOTPUD) {
Expand All @@ -209,7 +219,7 @@ bool FastDeployModel::InitRuntimeWithSpecifiedDevice() {
#endif
}
FDERROR << "Only support "
"CPU/GPU/IPU/RKNPU/HORIZONNPU/TIMVX/KunlunXin/ASCEND/DirectML/CoreML now."
"CPU/GPU/IPU/RKNPU/HORIZONNPU/TIMVX/KunlunXin/ASCEND/DirectML/CoreML/WebGPU now."
<< std::endl;
return false;
}
Expand Down Expand Up @@ -461,6 +471,30 @@ bool FastDeployModel::CreateCoreMLBackend() {
return false;
}

bool FastDeployModel::CreateWebGPUBackend() {
if (valid_webgpu_backends.size() == 0) {
FDERROR << "There's no valid webgpu backends for model: " << ModelName()
<< std::endl;
return false;
}

for (size_t i = 0; i < valid_webgpu_backends.size(); ++i) {
if (!IsBackendAvailable(valid_webgpu_backends[i])) {
continue;
}
runtime_option.backend = valid_webgpu_backends[i];
runtime_ = std::unique_ptr<Runtime>(new Runtime());
if (!runtime_->Init(runtime_option)) {
return false;
}
runtime_initialized_ = true;
return true;
}
FDERROR << "Found no valid webgpu backend for model: " << ModelName()
<< std::endl;
return false;
}

bool FastDeployModel::CreateIpuBackend() {
if (valid_ipu_backends.size() == 0) {
FDERROR << "There's no valid ipu backends for model: " << ModelName()
Expand Down
4 changes: 4 additions & 0 deletions fastdeploy/fastdeploy_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class FASTDEPLOY_DECL FastDeployModel {
/** Model's valid coreml backends. This member defined all the onnxruntime coreml backends have successfully tested for the model
*/
std::vector<Backend> valid_coreml_backends = {Backend::ORT};
/** Model's valid webgpu backends. This member defined all the onnxruntime webgpu backends have successfully tested for the model
*/
std::vector<Backend> valid_webgpu_backends = {Backend::ORT};
/** Model's valid ascend backends. This member defined all the cann backends have successfully tested for the model
*/
std::vector<Backend> valid_ascend_backends = {};
Expand Down Expand Up @@ -167,6 +170,7 @@ class FASTDEPLOY_DECL FastDeployModel {
bool CreateASCENDBackend();
bool CreateDirectMLBackend();
bool CreateCoreMLBackend();
bool CreateWebGPUBackend();
bool IsSupported(const std::vector<Backend>& backends,
Backend backend);

Expand Down
2 changes: 1 addition & 1 deletion fastdeploy/runtime/backends/ort/option.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ struct OrtBackendOption {
* \note Complete Takeover Semantics: If this callback is provided, OrtBackend::BuildOption
* invokes it and returns immediately. All standard configurations in OrtBackendOption
* (e.g., intra/inter op threads, graph optimization level, execution providers like
* DirectML/CoreML/CUDA) will be completely bypassed. The caller is responsible for
* DirectML/CoreML/CUDA/WebGPU) will be completely bypassed. The caller is responsible for
* fully configuring the session_options.
*/
bool (*configure_session_callback)(OrtSessionOptions* session_options, void* user_data) = nullptr;
Expand Down
77 changes: 75 additions & 2 deletions fastdeploy/runtime/backends/ort/ort_backend.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,18 @@
#include <coreml_provider_factory.h>
#endif

// The linked ONNX Runtime installs <webgpu_provider_factory.h> only when the
// WebGPU EP is part of that build (see get_c_cxx_api_headers() in ORT's
// cmake/onnxruntime.cmake). That file is a pure marker -- it declares nothing,
// and unlike DML/CoreML there is no dedicated WebGPU factory to call: the EP
// goes through the generic SessionOptionsAppendExecutionProvider. So probe it
// instead of including it.
#if defined(WITH_WEBGPU) && __has_include(<webgpu_provider_factory.h>)
#define ENABLE_WEBGPU
#endif

#include <memory>
#include <unordered_map>

namespace fastdeploy {

Expand Down Expand Up @@ -190,15 +201,69 @@ bool OrtBackend::BuildOption(const OrtBackendOption& option) {
return true;
}
#endif
#ifdef ENABLE_WEBGPU
// If use WebGPU
else if (option.device == Device::WEBGPU) {
auto all_providers = Ort::GetAvailableProviders();
bool support_webgpu = false;
std::string providers_msg = "";
for (size_t i = 0; i < all_providers.size(); ++i) {
providers_msg = providers_msg + all_providers[i] + ", ";
if (all_providers[i] == "WebGpuExecutionProvider") {
support_webgpu = true;
}
}

if (!support_webgpu) {
FDWARNING << "Compiled fastdeploy with onnxruntime doesn't "
"support WebGPU, the available providers are "
<< providers_msg << "will fallback to CPUExecutionProvider."
<< "Please check if onnxruntime is built with WebGPU support."
<< std::endl;
option_.device = Device::CPU;
} else {
try {
// OrtSessionOptionsAppendExecutionProvider turns each key into
// "ep.webgpuexecutionprovider.<key>", and the WebGPU EP only reads the
// camelCase key "deviceId". A snake_case "device_id" is silently
// ignored by ONNX Runtime.
std::unordered_map<std::string, std::string> webgpu_options;
if (option_.device_id > 0) {
webgpu_options["deviceId"] = std::to_string(option_.device_id);
}
session_options_.AppendExecutionProvider("WebGPU", webgpu_options);
} catch (const std::exception& e) {
FDERROR << "Failed to append WebGPU execution provider: " << e.what()
<< std::endl;
return false;
}
}
return true;
}
#else
// The ONNX Runtime this build links does not ship the WebGPU EP (see the
// provider factory probe at the top of this file), so the device is
// unavailable. Keep the same soft-fallback contract as the runtime check
// above, but say why.
else if (option.device == Device::WEBGPU) {
FDWARNING << "FastDeploy was built without WebGPU support: the linked "
"onnxruntime has no WebGpuExecutionProvider. Fallback to "
"CPUExecutionProvider. Rebuild against an ONNX Runtime built "
"with --use_webgpu to use Device::WEBGPU."
<< std::endl;
option_.device = Device::CPU;
}
#endif

return true;
}

bool OrtBackend::Init(const RuntimeOption& option) {
if (option.device != Device::CPU && option.device != Device::CUDA &&
option.device != Device::DIRECTML && option.device != Device::COREML) {
option.device != Device::DIRECTML && option.device != Device::COREML &&
option.device != Device::WEBGPU) {
FDERROR
<< "Backend::ORT only supports Device::CPU/Device::CUDA/Device::DIRECTML/Device::COREML, but now its "
<< "Backend::ORT only supports Device::CPU/Device::CUDA/Device::DIRECTML/Device::COREML/Device::WEBGPU, but now its "
<< option.device << "." << std::endl;
return false;
}
Expand Down Expand Up @@ -530,6 +595,14 @@ void OrtBackend::InitCustomOperators() {
AdaptivePool2dOp* adaptive_pool2d =
new AdaptivePool2dOp{"CoreMLExecutionProvider"};
custom_operators_.push_back(adaptive_pool2d);
} else if (option_.device == Device::WEBGPU) {
// Must be the EP type name registered by ONNX Runtime
// ("WebGpuExecutionProvider"), not the "WebGPU" short name accepted by
// SessionOptions::AppendExecutionProvider: custom kernels are looked up
// by Node::GetExecutionProviderType().
AdaptivePool2dOp* adaptive_pool2d =
new AdaptivePool2dOp{"WebGpuExecutionProvider"};
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
custom_operators_.push_back(adaptive_pool2d);
} else {
AdaptivePool2dOp* adaptive_pool2d =
new AdaptivePool2dOp{"CPUExecutionProvider"};
Expand Down
6 changes: 3 additions & 3 deletions fastdeploy/runtime/backends/ort/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ FDDataType GetFdDtype(const ONNXTensorElementDataType& ort_dtype) {
}

Ort::Value CreateOrtValue(FDTensor& tensor) {
FDASSERT(tensor.device == Device::CUDA || tensor.device == Device::DIRECTML || tensor.device == Device::COREML || tensor.device == Device::CPU,
"Only support tensor which device is Cuda or DirectML or CPU for OrtBackend.");
FDASSERT(tensor.device == Device::CUDA || tensor.device == Device::DIRECTML || tensor.device == Device::COREML || tensor.device == Device::WEBGPU || tensor.device == Device::CPU,
"Only support tensor which device is Cuda or DirectML or CoreML or WebGPU or CPU for OrtBackend.");
if (tensor.device == Device::CUDA) {
Ort::MemoryInfo memory_info("Cuda", OrtDeviceAllocator, 0,
OrtMemTypeDefault);
Expand All @@ -78,7 +78,7 @@ Ort::Value CreateOrtValue(FDTensor& tensor) {
tensor.shape.size(), GetOrtDtype(tensor.dtype));
return ort_value;
}
else { // not support coreml now
else { // CoreML/WebGPU/CPU tensors live in host memory
Ort::MemoryInfo memory_info("Cpu", OrtDeviceAllocator, 0, OrtMemTypeDefault);
auto ort_value = Ort::Value::CreateTensor(
memory_info, tensor.Data(), tensor.Nbytes(), tensor.shape.data(),
Expand Down
3 changes: 3 additions & 0 deletions fastdeploy/runtime/enum_variables.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ std::ostream& operator<<(std::ostream& out, const Device& d) {
case Device::COREML:
out << "Device::COREML";
break;
case Device::WEBGPU:
out << "Device::WEBGPU";
break;
default:
out << "Device::UNKOWN";
}
Expand Down
6 changes: 4 additions & 2 deletions fastdeploy/runtime/enum_variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace fastdeploy {
enum Backend {
UNKNOWN, ///< Unknown inference backend
ORT, //< ONNX Runtime, support Paddle/ONNX format model,
//< CPU/ Nvidia GPU DirectML/CoreML
//< CPU/ Nvidia GPU DirectML/CoreML/WebGPU
TRT, ///< TensorRT, support Paddle/ONNX format model, Nvidia GPU only
PDINFER, ///< Paddle Inference, support Paddle format model, CPU / Nvidia GPU
POROS, ///< Poros, support TorchScript format model, CPU / Nvidia GPU
Expand Down Expand Up @@ -65,6 +65,7 @@ enum FASTDEPLOY_DECL Device {
DIRECTML,
COREML,
SUNRISENPU,
WEBGPU,
};

/*! Deep learning model format */
Expand Down Expand Up @@ -107,7 +108,8 @@ static std::map<Device, std::vector<Backend>>
{Device::ASCEND, {Backend::LITE}},
{Device::SOPHGOTPUD, {Backend::SOPHGOTPU}},
{Device::DIRECTML, {Backend::ORT}},
{Device::COREML, {Backend::ORT}}
{Device::COREML, {Backend::ORT}},
{Device::WEBGPU, {Backend::ORT}}
};

inline bool Supported(ModelFormat format, Backend backend) {
Expand Down
5 changes: 5 additions & 0 deletions fastdeploy/runtime/runtime_option.cc
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ void RuntimeOption::UseCoreML(uint32_t coreml_flag) {
device_id = coreml_flag;
}

void RuntimeOption::UseWebGPU(int device_id) {
device = Device::WEBGPU;
this->device_id = device_id;
}

void RuntimeOption::UseSophgo() {
device = Device::SOPHGOTPUD;
UseSophgoBackend();
Expand Down
3 changes: 3 additions & 0 deletions fastdeploy/runtime/runtime_option.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ struct FASTDEPLOY_DECL RuntimeOption {
/// Use onnxruntime CoreML to inference
void UseCoreML(uint32_t coreml_flag = 0);

/// Use onnxruntime WebGPU to inference
void UseWebGPU(int device_id = 0);

/// Use Sophgo to inference
void UseSophgo();
/// \brief Turn on KunlunXin XPU.
Expand Down
Loading
Loading