Merge pull request #1 from microsoft/yguo/add-initial-files

Create initial contents for new onnxruntime-swift-package-manager repo
This commit is contained in:
Rachel Guo
2023-07-25 10:39:29 -07:00
committed by GitHub
32 changed files with 1824 additions and 8 deletions
+5
View File
@@ -396,3 +396,8 @@ FodyWeavers.xsd
# JetBrains Rider
*.sln.iml
.DS_Store
*.DS_Store
.build/
@@ -0,0 +1,72 @@
jobs:
- job: j
displayName: "Test with latest local ORT native pod"
pool:
vmImage: "macOS-13"
variables:
xcodeVersion: "14.3"
artifactsName: "ios_packaging_artifacts_full"
timeoutInMinutes: 60
steps:
- template: templates/use-xcode-version.yml
parameters:
xcodeVersion: ${{ variables.xcodeVersion }}
- script: |
mkdir tmp
cd tmp
git clone -n --depth=1 --filter=tree:0 https://github.com/microsoft/onnxruntime.git
cd onnxruntime
git sparse-checkout set --no-cone objectivec swift Package.swift
git checkout
workingDirectory: "$(Build.SourcesDirectory)"
displayName: "Sparse checkout objectivec/ swift/ folders from latest ORT main repository"
- script: |
ls -R "$(Build.SourcesDirectory)/tmp/onnxruntime"
workingDirectory: "$(Build.SourcesDirectory)/tmp"
displayName: "List sparse checkout repo contents"
# Download artifacts from a specific pipeline
# For now, it consumes rel-1.15.0 version ORT iOS Pod which matches the current source code
# TODO: Update branch to latest main of ORT github repo when syncing changes to ORT SPM repo here.
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'specific'
project: 'Lotus'
definition: 995 #'definitionid' is obtained from `System.DefinitionId` of ORT CI: onnxruntime-ios-packaging-pipeline
buildVersionToDownload: 'latest'
branchName: 'main'
targetPath: '$(Build.ArtifactStagingDirectory)'
- script: |
set -e -x
ls
workingDirectory: '$(Build.ArtifactStagingDirectory)/$(artifactsName)'
displayName: "List staged artifacts"
# copy the pod archive to a path relative to Package.swift and set the env var required by Package.swift to use that.
# xcodebuild will implicitly use Package.swift and build/run the .testTarget (tests in swift/onnxTests).
# once that's done cleanup the copy of the pod zip file
- script: |
set -e -x
cd "$(Build.ArtifactStagingDirectory)/$(artifactsName)"
POD_ARCHIVE=$(find . -name "pod-archive-onnxruntime-c*.zip")
shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}"
cd "$(Build.SourcesDirectory)/tmp/onnxruntime"
cp "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" swift/
export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}"
xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14'
rm swift/pod-archive-onnxruntime-c-*.zip
workingDirectory: "$(Build.SourcesDirectory)/tmp"
displayName: "Print ORT iOS Pod checksum and Test Package.swift usage"
- template: templates/component-governance-component-detection-steps.yml
parameters :
condition : 'succeeded'
@@ -0,0 +1,26 @@
jobs:
- job: j
displayName: "Test with released ORT native pod"
pool:
vmImage: "macOS-13"
variables:
xcodeVersion: "14.3"
timeoutInMinutes: 60
steps:
- template: templates/use-xcode-version.yml
parameters:
xcodeVersion: ${{ variables.xcodeVersion }}
- script: |
set -e -x
xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14'
workingDirectory: "$(Build.SourcesDirectory)"
displayName: "Test Package.swift usage"
- template: templates/component-governance-component-detection-steps.yml
parameters :
condition : 'succeeded'
@@ -0,0 +1,14 @@
# component detection for component governance checks
parameters:
- name: condition
type: string
default: 'succeeded' # could be 'ci_only', 'always', 'succeeded'
steps:
- ${{ if eq(variables['System.TeamProject'], 'Lotus') }}:
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
displayName: 'Component Detection'
condition:
or(or(and(eq('${{parameters.condition}}', 'ci_only'), and(succeeded(), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'Scheduled'))),
and(eq('${{parameters.condition}}', 'always'), always())),
and(eq('${{parameters.condition}}', 'succeeded'), succeeded()))
@@ -0,0 +1,14 @@
# Specify use of a specific Xcode version.
parameters:
- name: xcodeVersion
type: string
default: "14.3"
steps:
- bash: |
set -e -x
XCODE_DEVELOPER_DIR="/Applications/Xcode_${{ parameters.xcodeVersion }}.app/Contents/Developer"
sudo xcode-select --switch "${XCODE_DEVELOPER_DIR}"
displayName: Use Xcode ${{ parameters.xcodeVersion }}
+86
View File
@@ -0,0 +1,86 @@
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package and MUST be the first
// line of this file. 5.6 is required to support zip files for the pod archive binaryTarget.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// A user of the Swift Package Manager (SPM) package will consume this file directly from the ORT github repository.
// For context, the end user's config will look something like:
//
// dependencies: [
// #TODO: update to use release 'version' and the new repo url here when available
// .package(url: "https://github.com/microsoft/onnxruntime", branch: "rel-1.15.0"),
// ...
// ],
//
import PackageDescription
import class Foundation.ProcessInfo
let package = Package(
name: "onnxruntime",
platforms: [.iOS(.v11)],
products: [
.library(name: "onnxruntime",
type: .static,
targets: ["OnnxRuntimeBindings"]),
],
dependencies: [],
targets: [
.target(name: "OnnxRuntimeBindings",
dependencies: ["onnxruntime"],
path: "objectivec",
exclude: ["ReadMe.md", "format_objc.sh"],
cxxSettings: [
.define("SPM_BUILD"),
.unsafeFlags(["-std=c++17",
"-fobjc-arc-exceptions"
]),
], linkerSettings: [
.unsafeFlags(["-ObjC"]),
]),
.testTarget(name: "OnnxRuntimeBindingsTests",
dependencies: ["OnnxRuntimeBindings"],
path: "swift/OnnxRuntimeBindingsTests",
resources: [
.copy("Resources/single_add.basic.ort")
]),
]
)
// Add the ORT iOS Pod archive as a binary target.
//
// There are 2 scenarios:
//
// Release version of ORT SPM github repo:
// Target will be set to the latest released ORT iOS pod archive and its checksum.
//
// Current main of ORT SPM github repo:
// Target will be set to the pod archive built in sync with the current main objective-c source code.
// CI or local testing where you have built/obtained the iOS Pod archive matching the current source code.
// Requires the ORT_IOS_POD_LOCAL_PATH environment variable to be set to specify the location of the pod.
if let pod_archive_path = ProcessInfo.processInfo.environment["ORT_IOS_POD_LOCAL_PATH"] {
// ORT_IOS_POD_LOCAL_PATH MUST be a path that is relative to Package.swift.
//
// To build locally, tools/ci_build/github/apple/build_and_assemble_ios_pods.py can be used
// See https://onnxruntime.ai/docs/build/custom.html#ios
// Example command:
// python3 tools/ci_build/github/apple/build_and_assemble_ios_pods.py \
// --variant Full \
// --build-settings-file tools/ci_build/github/apple/default_full_ios_framework_build_settings.json
//
// This should produce the pod archive in build/ios_pod_staging, and ORT_IOS_POD_LOCAL_PATH can be set to
// "build/ios_pod_staging/pod-archive-onnxruntime-c-???.zip" where '???' is replaced by the version info in the
// actual filename.
package.targets.append(Target.binaryTarget(name: "onnxruntime", path: pod_archive_path))
} else {
// ORT 1.15.0 release
package.targets.append(
Target.binaryTarget(name: "onnxruntime",
url: "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-1.15.0.zip",
checksum: "9b41412329a73d7d298b1d94ab40ae9adb65cb84f132054073bc82515b4f5f82")
)
}
+7 -8
View File
@@ -1,14 +1,13 @@
# Project
# Swift Package Manager for ONNX Runtime
> This repo has been populated by an initial template to help get you started. Please
> make sure to update the content to build a great experience for community-building.
A light-weight repository for providing [Swift Package Manager (SPM)](https://www.swift.org/package-manager/) support for [ONNXRuntime](https://github.com/microsoft/onnxruntime). The ONNX Runtime native package is included as a binary dependency of the SPM package.
As the maintainer of this project, please make a few updates:
- Improving this README.MD file to provide a great experience
- Updating SUPPORT.MD with content about this project's support experience
- Understanding the security reporting process in SECURITY.MD
- Remove this section from the README
SPM is the alternative to CocoaPods when desired platform to consume is mobile iOS.
## Note
The `objectivec/` and `swift/` directories are copied from ORT repo and it's expected to match. It will be updated periodically/before release to merge the newly checked-in changes for objective-c/swift on ORT main repo.
## Contributing
+2
View File
@@ -0,0 +1,2 @@
NOTE: Flat directory structure to work with both the Objective-C build and the Swift Package Manager build which is done
via ../Package.swift
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled.");
+41
View File
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// wrapper for ORT C/C++ API headers
#if defined(__clang__)
#pragma clang diagnostic push
// ignore clang documentation-related warnings
// instead, we will rely on Doxygen warnings for the C/C++ API headers
#pragma clang diagnostic ignored "-Wdocumentation"
#endif // defined(__clang__)
// paths are different when building the Swift Package Manager package as the headers come from the iOS pod archive
#ifdef SPM_BUILD
#include "onnxruntime/onnxruntime_c_api.h"
#include "onnxruntime/onnxruntime_cxx_api.h"
#if __has_include("onnxruntime/coreml_provider_factory.h")
#define ORT_OBJC_API_COREML_EP_AVAILABLE 1
#include "onnxruntime/coreml_provider_factory.h"
#else
#define ORT_OBJC_API_COREML_EP_AVAILABLE 0
#endif
#else
#include "onnxruntime_c_api.h"
#include "onnxruntime_cxx_api.h"
#if __has_include("coreml_provider_factory.h")
#define ORT_OBJC_API_COREML_EP_AVAILABLE 1
#include "coreml_provider_factory.h"
#else
#define ORT_OBJC_API_COREML_EP_AVAILABLE 0
#endif
#endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif // defined(__clang__)
+33
View File
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#include <exception>
#import "cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
void ORTSaveCodeAndDescriptionToError(int code, const char* description, NSError** error);
void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error);
void ORTSaveExceptionToError(const std::exception& e, NSError** error);
// helper macros to catch and handle C++ exceptions
#define ORT_OBJC_API_IMPL_CATCH(error, failure_return_value) \
catch (const Ort::Exception& e) { \
ORTSaveOrtExceptionToError(e, (error)); \
return (failure_return_value); \
} \
catch (const std::exception& e) { \
ORTSaveExceptionToError(e, (error)); \
return (failure_return_value); \
}
#define ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) \
ORT_OBJC_API_IMPL_CATCH(error, NO)
#define ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) \
ORT_OBJC_API_IMPL_CATCH(error, nil)
NS_ASSUME_NONNULL_END
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "error_utils.h"
NS_ASSUME_NONNULL_BEGIN
static NSString* const kOrtErrorDomain = @"onnxruntime";
void ORTSaveCodeAndDescriptionToError(int code, const char* descriptionCstr, NSError** error) {
if (!error) return;
NSString* description = [NSString stringWithCString:descriptionCstr
encoding:NSASCIIStringEncoding];
*error = [NSError errorWithDomain:kOrtErrorDomain
code:code
userInfo:@{NSLocalizedDescriptionKey : description}];
}
void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error) {
ORTSaveCodeAndDescriptionToError(e.GetOrtErrorCode(), e.what(), error);
}
void ORTSaveExceptionToError(const std::exception& e, NSError** error) {
ORTSaveCodeAndDescriptionToError(ORT_RUNTIME_EXCEPTION, e.what(), error);
}
NS_ASSUME_NONNULL_END
+9
View File
@@ -0,0 +1,9 @@
#!/bin/bash
# formats Objective-C/C++ code
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
clang-format -i $(find ${SCRIPT_DIR} -name "*.h" -o -name "*.m" -o -name "*.mm")
+12
View File
@@ -0,0 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// this header contains the entire ONNX Runtime Objective-C API
// the headers below can also be imported individually
#import "ort_coreml_execution_provider.h"
#import "ort_xnnpack_execution_provider.h"
#import "ort_enums.h"
#import "ort_env.h"
#import "ort_session.h"
#import "ort_value.h"
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "ort_session.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Gets whether the CoreML execution provider is available.
*/
BOOL ORTIsCoreMLExecutionProviderAvailable(void);
#ifdef __cplusplus
}
#endif
NS_ASSUME_NONNULL_BEGIN
/**
* Options for configuring the CoreML execution provider.
*/
@interface ORTCoreMLExecutionProviderOptions : NSObject
/**
* Whether the CoreML execution provider should run on CPU only.
*/
@property BOOL useCPUOnly;
/**
* Whether the CoreML execution provider is enabled on subgraphs.
*/
@property BOOL enableOnSubgraphs;
/**
* Whether the CoreML execution provider is only enabled for devices with Apple
* Neural Engine (ANE).
*/
@property BOOL onlyEnableForDevicesWithANE;
@end
@interface ORTSessionOptions (ORTSessionOptionsCoreMLEP)
/**
* Enables the CoreML execution provider in the session configuration options.
* It is appended to the execution provider list which is ordered by
* decreasing priority.
*
* @param options The CoreML execution provider configuration options.
* @param error Optional error information set if an error occurs.
* @return Whether the provider was enabled successfully.
*/
- (BOOL)appendCoreMLExecutionProviderWithOptions:(ORTCoreMLExecutionProviderOptions*)options
error:(NSError**)error;
@end
NS_ASSUME_NONNULL_END
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
/**
* The ORT logging verbosity levels.
*/
typedef NS_ENUM(int32_t, ORTLoggingLevel) {
ORTLoggingLevelVerbose,
ORTLoggingLevelInfo,
ORTLoggingLevelWarning,
ORTLoggingLevelError,
ORTLoggingLevelFatal,
};
/**
* The ORT value types.
* Currently, a subset of all types is supported.
*/
typedef NS_ENUM(int32_t, ORTValueType) {
ORTValueTypeUnknown,
ORTValueTypeTensor,
};
/**
* The ORT tensor element data types.
* Currently, a subset of all types is supported.
*/
typedef NS_ENUM(int32_t, ORTTensorElementDataType) {
ORTTensorElementDataTypeUndefined,
ORTTensorElementDataTypeFloat,
ORTTensorElementDataTypeInt8,
ORTTensorElementDataTypeUInt8,
ORTTensorElementDataTypeInt32,
ORTTensorElementDataTypeUInt32,
ORTTensorElementDataTypeInt64,
ORTTensorElementDataTypeUInt64,
};
/**
* The ORT graph optimization levels.
* See here for more details:
* https://onnxruntime.ai/docs/performance/graph-optimizations.html
*/
typedef NS_ENUM(int32_t, ORTGraphOptimizationLevel) {
ORTGraphOptimizationLevelNone,
ORTGraphOptimizationLevelBasic,
ORTGraphOptimizationLevelExtended,
ORTGraphOptimizationLevelAll,
};
NS_ASSUME_NONNULL_END
+44
View File
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "ort_enums.h"
NS_ASSUME_NONNULL_BEGIN
#ifdef __cplusplus
extern "C" {
#endif
/**
* Gets the ORT version string in format major.minor.patch.
*
* Available since 1.15.
*/
NSString* ORTVersion(void);
#ifdef __cplusplus
}
#endif
/**
* The ORT environment.
*/
@interface ORTEnv : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates an ORT Environment.
*
* @param loggingLevel The environment logging level.
* @param error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithLoggingLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
@end
NS_ASSUME_NONNULL_END
+266
View File
@@ -0,0 +1,266 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "ort_enums.h"
NS_ASSUME_NONNULL_BEGIN
@class ORTEnv;
@class ORTRunOptions;
@class ORTSessionOptions;
@class ORTValue;
/**
* An ORT session loads and runs a model.
*/
@interface ORTSession : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a session.
*
* @param env The ORT Environment instance.
* @param path The path to the ONNX model.
* @param sessionOptions Optional session configuration options.
* @param error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithEnv:(ORTEnv*)env
modelPath:(NSString*)path
sessionOptions:(nullable ORTSessionOptions*)sessionOptions
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
/**
* Runs the model.
* The inputs and outputs are pre-allocated.
*
* @param inputs Dictionary of input names to input ORT values.
* @param outputs Dictionary of output names to output ORT values.
* @param runOptions Optional run configuration options.
* @param error Optional error information set if an error occurs.
* @return Whether the model was run successfully.
*/
- (BOOL)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputs:(NSDictionary<NSString*, ORTValue*>*)outputs
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error;
/**
* Runs the model.
* The inputs are pre-allocated and the outputs are allocated by ORT.
*
* @param inputs Dictionary of input names to input ORT values.
* @param outputNames Set of output names.
* @param runOptions Optional run configuration options.
* @param error Optional error information set if an error occurs.
* @return A dictionary of output names to output ORT values with the outputs
* requested in `outputNames`, or nil if an error occurs.
*/
- (nullable NSDictionary<NSString*, ORTValue*>*)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputNames:(NSSet<NSString*>*)outputNames
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error;
/**
* Gets the model's input names.
*
* @param error Optional error information set if an error occurs.
* @return An array of input names, or nil if an error occurs.
*/
- (nullable NSArray<NSString*>*)inputNamesWithError:(NSError**)error;
/**
* Gets the model's overridable initializer names.
*
* @param error Optional error information set if an error occurs.
* @return An array of overridable initializer names, or nil if an error occurs.
*/
- (nullable NSArray<NSString*>*)overridableInitializerNamesWithError:(NSError**)error;
/**
* Gets the model's output names.
*
* @param error Optional error information set if an error occurs.
* @return An array of output names, or nil if an error occurs.
*/
- (nullable NSArray<NSString*>*)outputNamesWithError:(NSError**)error;
@end
/**
* Options for configuring a session.
*/
@interface ORTSessionOptions : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates session configuration options.
*
* @param error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithError:(NSError**)error NS_SWIFT_NAME(init());
/**
* Appends an execution provider to the session options to enable the execution provider to be used when running
* the model.
*
* Available since 1.14.
*
* The execution provider list is ordered by decreasing priority.
* i.e. the first provider registered has the highest priority.
*
* @param providerName Provider name. For example, "xnnpack".
* @param providerOptions Provider-specific options. For example, for provider "xnnpack", {"intra_op_num_threads": "2"}.
* @param error Optional error information set if an error occurs.
* @return Whether the execution provider was appended successfully
*/
- (BOOL)appendExecutionProvider:(NSString*)providerName
providerOptions:(NSDictionary<NSString*, NSString*>*)providerOptions
error:(NSError**)error;
/**
* Sets the number of threads used to parallelize the execution within nodes.
* A value of 0 means ORT will pick a default value.
*
* @param intraOpNumThreads The number of threads.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setIntraOpNumThreads:(int)intraOpNumThreads
error:(NSError**)error;
/**
* Sets the graph optimization level.
*
* @param graphOptimizationLevel The graph optimization level.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setGraphOptimizationLevel:(ORTGraphOptimizationLevel)graphOptimizationLevel
error:(NSError**)error;
/**
* Sets the path to which the optimized model file will be saved.
*
* @param optimizedModelFilePath The optimized model file path.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setOptimizedModelFilePath:(NSString*)optimizedModelFilePath
error:(NSError**)error;
/**
* Sets the session log ID.
*
* @param logID The log ID.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setLogID:(NSString*)logID
error:(NSError**)error;
/**
* Sets the session log severity level.
*
* @param loggingLevel The log severity level.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error;
/**
* Sets a session configuration key-value pair.
* Any value for a previously set key will be overwritten.
* The session configuration keys and values are documented here:
* https://github.com/microsoft/onnxruntime/blob/main/include/onnxruntime/core/session/onnxruntime_session_options_config_keys.h
*
* @param key The key.
* @param value The value.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error;
/**
* Registers custom ops for use with `ORTSession`s using this SessionOptions by calling the specified
* native function name. The custom ops library must either be linked against, or have previously been loaded
* by the user.
*
* Available since 1.14.
*
* The registration function must have the signature:
* OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);
*
* See https://onnxruntime.ai/docs/reference/operators/add-custom-op.html for more information on custom ops.
* See https://github.com/microsoft/onnxruntime/blob/342a5bf2b756d1a1fc6fdc582cfeac15182632fe/onnxruntime/test/testdata/custom_op_library/custom_op_library.cc#L115
* for an example of a custom op library registration function.
*
* @param registrationFuncName The name of the registration function to call.
* @param error Optional error information set if an error occurs.
* @return Whether the registration function was successfully called.
*/
- (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName
error:(NSError**)error;
@end
/**
* Options for configuring a run.
*/
@interface ORTRunOptions : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates run configuration options.
*
* @param error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithError:(NSError**)error NS_SWIFT_NAME(init());
/**
* Sets the run log tag.
*
* @param logTag The log tag.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setLogTag:(NSString*)logTag
error:(NSError**)error;
/**
* Sets the run log severity level.
*
* @param loggingLevel The log severity level.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error;
/**
* Sets a run configuration key-value pair.
* Any value for a previously set key will be overwritten.
* The run configuration keys and values are documented here:
* https://github.com/microsoft/onnxruntime/blob/main/include/onnxruntime/core/session/onnxruntime_run_options_config_keys.h
*
* @param key The key.
* @param value The value.
* @param error Optional error information set if an error occurs.
* @return Whether the option was set successfully.
*/
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error;
@end
NS_ASSUME_NONNULL_END
+94
View File
@@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "ort_enums.h"
NS_ASSUME_NONNULL_BEGIN
@class ORTValueTypeInfo;
@class ORTTensorTypeAndShapeInfo;
/**
* An ORT value encapsulates data used as an input or output to a model at runtime.
*/
@interface ORTValue : NSObject
- (instancetype)init NS_UNAVAILABLE;
/**
* Creates a value that is a tensor.
* The tensor data is allocated by the caller.
*
* @param tensorData The tensor data.
* @param elementType The tensor element data type.
* @param shape The tensor shape.
* @param error Optional error information set if an error occurs.
* @return The instance, or nil if an error occurs.
*/
- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData
elementType:(ORTTensorElementDataType)elementType
shape:(NSArray<NSNumber*>*)shape
error:(NSError**)error;
/**
* Gets the type information.
*
* @param error Optional error information set if an error occurs.
* @return The type information, or nil if an error occurs.
*/
- (nullable ORTValueTypeInfo*)typeInfoWithError:(NSError**)error;
/**
* Gets the tensor type and shape information.
* This assumes that the value is a tensor.
*
* @param error Optional error information set if an error occurs.
* @return The tensor type and shape information, or nil if an error occurs.
*/
- (nullable ORTTensorTypeAndShapeInfo*)tensorTypeAndShapeInfoWithError:(NSError**)error;
/**
* Gets the tensor data.
* This assumes that the value is a tensor.
*
* This returns the value's underlying data directly, not a copy of it.
* The memory's lifetime may be tied to this value, i.e., if it was allocated
* by ORT. On the other hand, the memory's lifetime is independent of the value
* if the value was created with user-provided data.
*
* @param error Optional error information set if an error occurs.
* @return The tensor data, or nil if an error occurs.
*/
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error;
@end
/**
* A value's type information.
*/
@interface ORTValueTypeInfo : NSObject
/** The value type. */
@property(nonatomic) ORTValueType type;
/** The tensor type and shape information, if the value is a tensor. */
@property(nonatomic, nullable) ORTTensorTypeAndShapeInfo* tensorTypeAndShapeInfo;
@end
/**
* A tensor's type and shape information.
*/
@interface ORTTensorTypeAndShapeInfo : NSObject
/** The tensor element data type. */
@property(nonatomic) ORTTensorElementDataType elementType;
/** The tensor shape. */
@property(nonatomic) NSArray<NSNumber*>* shape;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,39 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <Foundation/Foundation.h>
#import "ort_session.h"
NS_ASSUME_NONNULL_BEGIN
/**
* Options for configuring the Xnnpack execution provider.
*/
@interface ORTXnnpackExecutionProviderOptions : NSObject
/**
* How many threads used for the Xnnpack execution provider.
*/
@property int intra_op_num_threads;
@end
@interface ORTSessionOptions (ORTSessionOptionsXnnpackEP)
/**
* Available since 1.14.
* Enables the Xnnpack execution provider in the session configuration options.
* It is appended to the execution provider list which is ordered by
* decreasing priority.
*
* @param options The Xnnpack execution provider configuration options.
* @param error Optional error information set if an error occurs.
* @return Whether the provider was enabled successfully.
*/
- (BOOL)appendXnnpackExecutionProviderWithOptions:(ORTXnnpackExecutionProviderOptions*)options
error:(NSError**)error;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_coreml_execution_provider.h"
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_session_internal.h"
NS_ASSUME_NONNULL_BEGIN
BOOL ORTIsCoreMLExecutionProviderAvailable() {
return ORT_OBJC_API_COREML_EP_AVAILABLE ? YES : NO;
}
@implementation ORTCoreMLExecutionProviderOptions
@end
@implementation ORTSessionOptions (ORTSessionOptionsCoreMLEP)
- (BOOL)appendCoreMLExecutionProviderWithOptions:(ORTCoreMLExecutionProviderOptions*)options
error:(NSError**)error {
#if ORT_OBJC_API_COREML_EP_AVAILABLE
try {
const uint32_t flags =
(options.useCPUOnly ? COREML_FLAG_USE_CPU_ONLY : 0) |
(options.enableOnSubgraphs ? COREML_FLAG_ENABLE_ON_SUBGRAPH : 0) |
(options.onlyEnableForDevicesWithANE ? COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE : 0);
Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CoreML(
[self CXXAPIOrtSessionOptions], flags));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error);
#else // !ORT_OBJC_API_COREML_EP_AVAILABLE
static_cast<void>(options);
ORTSaveCodeAndDescriptionToError(ORT_FAIL, "CoreML execution provider is not enabled.", error);
return NO;
#endif
}
@end
NS_ASSUME_NONNULL_END
+133
View File
@@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_enums_internal.h"
#include <algorithm>
#import "cxx_api.h"
namespace {
struct LoggingLevelInfo {
ORTLoggingLevel logging_level;
OrtLoggingLevel capi_logging_level;
};
// supported ORT logging levels
// define the mapping from ORTLoggingLevel to C API OrtLoggingLevel here
constexpr LoggingLevelInfo kLoggingLevelInfos[]{
{ORTLoggingLevelVerbose, ORT_LOGGING_LEVEL_VERBOSE},
{ORTLoggingLevelInfo, ORT_LOGGING_LEVEL_INFO},
{ORTLoggingLevelWarning, ORT_LOGGING_LEVEL_WARNING},
{ORTLoggingLevelError, ORT_LOGGING_LEVEL_ERROR},
{ORTLoggingLevelFatal, ORT_LOGGING_LEVEL_FATAL},
};
struct ValueTypeInfo {
ORTValueType type;
ONNXType capi_type;
};
// supported ORT value types
// define the mapping from ORTValueType to C API ONNXType here
constexpr ValueTypeInfo kValueTypeInfos[]{
{ORTValueTypeUnknown, ONNX_TYPE_UNKNOWN},
{ORTValueTypeTensor, ONNX_TYPE_TENSOR},
};
struct TensorElementTypeInfo {
ORTTensorElementDataType type;
ONNXTensorElementDataType capi_type;
size_t element_size;
};
// supported ORT tensor element data types
// define the mapping from ORTTensorElementDataType to C API ONNXTensorElementDataType here
constexpr TensorElementTypeInfo kElementTypeInfos[]{
{ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, 0},
{ORTTensorElementDataTypeFloat, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, sizeof(float)},
{ORTTensorElementDataTypeInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, sizeof(int8_t)},
{ORTTensorElementDataTypeUInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, sizeof(uint8_t)},
{ORTTensorElementDataTypeInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, sizeof(int32_t)},
{ORTTensorElementDataTypeUInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, sizeof(uint32_t)},
{ORTTensorElementDataTypeInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, sizeof(int64_t)},
{ORTTensorElementDataTypeUInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, sizeof(uint64_t)},
};
struct GraphOptimizationLevelInfo {
ORTGraphOptimizationLevel opt_level;
GraphOptimizationLevel capi_opt_level;
};
// ORT graph optimization levels
// define the mapping from ORTGraphOptimizationLevel to C API GraphOptimizationLevel here
constexpr GraphOptimizationLevelInfo kGraphOptimizationLevelInfos[]{
{ORTGraphOptimizationLevelNone, ORT_DISABLE_ALL},
{ORTGraphOptimizationLevelBasic, ORT_ENABLE_BASIC},
{ORTGraphOptimizationLevelExtended, ORT_ENABLE_EXTENDED},
{ORTGraphOptimizationLevelAll, ORT_ENABLE_ALL},
};
template <typename Container, typename SelectFn, typename TransformFn>
auto SelectAndTransform(
const Container& container, SelectFn select_fn, TransformFn transform_fn,
const char* not_found_msg)
-> decltype(transform_fn(*std::begin(container))) {
const auto it = std::find_if(
std::begin(container), std::end(container), select_fn);
if (it == std::end(container)) {
ORT_CXX_API_THROW(not_found_msg, ORT_NOT_IMPLEMENTED);
}
return transform_fn(*it);
}
} // namespace
OrtLoggingLevel PublicToCAPILoggingLevel(ORTLoggingLevel logging_level) {
return SelectAndTransform(
kLoggingLevelInfos,
[logging_level](const auto& logging_level_info) { return logging_level_info.logging_level == logging_level; },
[](const auto& logging_level_info) { return logging_level_info.capi_logging_level; },
"unsupported logging level");
}
ORTValueType CAPIToPublicValueType(ONNXType capi_type) {
return SelectAndTransform(
kValueTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.type; },
"unsupported value type");
}
ONNXTensorElementDataType PublicToCAPITensorElementType(ORTTensorElementDataType type) {
return SelectAndTransform(
kElementTypeInfos,
[type](const auto& type_info) { return type_info.type == type; },
[](const auto& type_info) { return type_info.capi_type; },
"unsupported tensor element type");
}
ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType capi_type) {
return SelectAndTransform(
kElementTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.type; },
"unsupported tensor element type");
}
size_t SizeOfCAPITensorElementType(ONNXTensorElementDataType capi_type) {
return SelectAndTransform(
kElementTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.element_size; },
"unsupported tensor element type");
}
GraphOptimizationLevel PublicToCAPIGraphOptimizationLevel(ORTGraphOptimizationLevel opt_level) {
return SelectAndTransform(
kGraphOptimizationLevelInfos,
[opt_level](const auto& opt_level_info) { return opt_level_info.opt_level == opt_level; },
[](const auto& opt_level_info) { return opt_level_info.capi_opt_level; },
"unsupported graph optimization level");
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_enums.h"
#import "cxx_api.h"
OrtLoggingLevel PublicToCAPILoggingLevel(ORTLoggingLevel logging_level);
ORTValueType CAPIToPublicValueType(ONNXType capi_type);
ONNXTensorElementDataType PublicToCAPITensorElementType(ORTTensorElementDataType type);
ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType capi_type);
size_t SizeOfCAPITensorElementType(ONNXTensorElementDataType capi_type);
GraphOptimizationLevel PublicToCAPIGraphOptimizationLevel(ORTGraphOptimizationLevel opt_level);
+44
View File
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_env_internal.h"
#include <optional>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
NS_ASSUME_NONNULL_BEGIN
NSString* ORTVersion(void) {
std::string result = OrtGetApiBase()->GetVersionString();
return [NSString stringWithUTF8String:result.c_str()];
}
@implementation ORTEnv {
std::optional<Ort::Env> _env;
}
- (nullable instancetype)initWithLoggingLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
const auto CAPILoggingLevel = PublicToCAPILoggingLevel(loggingLevel);
_env = Ort::Env{CAPILoggingLevel};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (Ort::Env&)CXXAPIOrtEnv {
return *_env;
}
@end
NS_ASSUME_NONNULL_END
+16
View File
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_env.h"
#import "cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTEnv ()
- (Ort::Env&)CXXAPIOrtEnv;
@end
NS_ASSUME_NONNULL_END
+361
View File
@@ -0,0 +1,361 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_session_internal.h"
#include <optional>
#include <vector>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
#import "ort_env_internal.h"
#import "ort_value_internal.h"
namespace {
enum class NamedValueType {
Input,
OverridableInitializer,
Output,
};
} // namespace
NS_ASSUME_NONNULL_BEGIN
@implementation ORTSession {
std::optional<Ort::Session> _session;
}
#pragma mark - Public
- (nullable instancetype)initWithEnv:(ORTEnv*)env
modelPath:(NSString*)path
sessionOptions:(nullable ORTSessionOptions*)sessionOptions
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
if (!sessionOptions) {
sessionOptions = [[ORTSessionOptions alloc] initWithError:error];
if (!sessionOptions) {
return nil;
}
}
_session = Ort::Session{[env CXXAPIOrtEnv],
path.UTF8String,
[sessionOptions CXXAPIOrtSessionOptions]};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputs:(NSDictionary<NSString*, ORTValue*>*)outputs
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error {
try {
if (!runOptions) {
runOptions = [[ORTRunOptions alloc] initWithError:error];
if (!runOptions) {
return NO;
}
}
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputs) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(static_cast<OrtValue*>([outputs[outputName] CXXAPIOrtValue]));
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions],
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (nullable NSDictionary<NSString*, ORTValue*>*)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputNames:(NSSet<NSString*>*)outputNameSet
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error {
try {
if (!runOptions) {
runOptions = [[ORTRunOptions alloc] initWithError:error];
if (!runOptions) {
return nil;
}
}
NSArray<NSString*>* outputNameArray = outputNameSet.allObjects;
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputNameArray) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(nullptr);
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions],
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
NSMutableDictionary<NSString*, ORTValue*>* outputs = [[NSMutableDictionary alloc] init];
for (NSUInteger i = 0; i < outputNameArray.count; ++i) {
ORTValue* outputValue = [[ORTValue alloc] initWithCAPIOrtValue:outputValues[i] externalTensorData:nil error:error];
if (!outputValue) {
// clean up remaining C API OrtValues which haven't been wrapped by an ORTValue yet
for (NSUInteger j = i; j < outputNameArray.count; ++j) {
Ort::GetApi().ReleaseValue(outputValues[j]);
}
return nil;
}
outputs[outputNameArray[i]] = outputValue;
}
return outputs;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable NSArray<NSString*>*)inputNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::Input error:error];
}
- (nullable NSArray<NSString*>*)overridableInitializerNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::OverridableInitializer error:error];
}
- (nullable NSArray<NSString*>*)outputNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::Output error:error];
}
#pragma mark - Private
- (nullable NSArray<NSString*>*)namesWithType:(NamedValueType)namedValueType
error:(NSError**)error {
try {
auto getCount = [&session = *_session, namedValueType]() {
if (namedValueType == NamedValueType::Input) {
return session.GetInputCount();
} else if (namedValueType == NamedValueType::OverridableInitializer) {
return session.GetOverridableInitializerCount();
} else {
return session.GetOutputCount();
}
};
auto getName = [&session = *_session, namedValueType](size_t i, OrtAllocator* allocator) {
if (namedValueType == NamedValueType::Input) {
return session.GetInputNameAllocated(i, allocator);
} else if (namedValueType == NamedValueType::OverridableInitializer) {
return session.GetOverridableInitializerNameAllocated(i, allocator);
} else {
return session.GetOutputNameAllocated(i, allocator);
}
};
const size_t nameCount = getCount();
Ort::AllocatorWithDefaultOptions allocator;
NSMutableArray<NSString*>* result = [NSMutableArray arrayWithCapacity:nameCount];
for (size_t i = 0; i < nameCount; ++i) {
auto name = getName(i, allocator);
NSString* nameNsstr = [NSString stringWithUTF8String:name.get()];
NSAssert(nameNsstr != nil, @"nameNsstr must not be nil");
[result addObject:nameNsstr];
}
return result;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
@end
@implementation ORTSessionOptions {
std::optional<Ort::SessionOptions> _sessionOptions;
}
#pragma mark - Public
- (nullable instancetype)initWithError:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_sessionOptions = Ort::SessionOptions{};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)appendExecutionProvider:(NSString*)providerName
providerOptions:(NSDictionary<NSString*, NSString*>*)providerOptions
error:(NSError**)error {
try {
std::unordered_map<std::string, std::string> options;
NSArray* keys = [providerOptions allKeys];
for (NSString* key in keys) {
NSString* value = [providerOptions objectForKey:key];
options.emplace(key.UTF8String, value.UTF8String);
}
_sessionOptions->AppendExecutionProvider(providerName.UTF8String, options);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error);
}
- (BOOL)setIntraOpNumThreads:(int)intraOpNumThreads
error:(NSError**)error {
try {
_sessionOptions->SetIntraOpNumThreads(intraOpNumThreads);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setGraphOptimizationLevel:(ORTGraphOptimizationLevel)graphOptimizationLevel
error:(NSError**)error {
try {
_sessionOptions->SetGraphOptimizationLevel(
PublicToCAPIGraphOptimizationLevel(graphOptimizationLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setOptimizedModelFilePath:(NSString*)optimizedModelFilePath
error:(NSError**)error {
try {
_sessionOptions->SetOptimizedModelFilePath(optimizedModelFilePath.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogID:(NSString*)logID
error:(NSError**)error {
try {
_sessionOptions->SetLogId(logID.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
try {
_sessionOptions->SetLogSeverityLevel(PublicToCAPILoggingLevel(loggingLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error {
try {
_sessionOptions->AddConfigEntry(key.UTF8String, value.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName
error:(NSError**)error {
try {
_sessionOptions->RegisterCustomOpsUsingFunction(registrationFuncName.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
#pragma mark - Internal
- (Ort::SessionOptions&)CXXAPIOrtSessionOptions {
return *_sessionOptions;
}
@end
@implementation ORTRunOptions {
std::optional<Ort::RunOptions> _runOptions;
}
#pragma mark - Public
- (nullable instancetype)initWithError:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_runOptions = Ort::RunOptions{};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)setLogTag:(NSString*)logTag
error:(NSError**)error {
try {
_runOptions->SetRunTag(logTag.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
try {
_runOptions->SetRunLogSeverityLevel(PublicToCAPILoggingLevel(loggingLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error {
try {
_runOptions->AddConfigEntry(key.UTF8String, value.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
#pragma mark - Internal
- (Ort::RunOptions&)CXXAPIOrtRunOptions {
return *_runOptions;
}
@end
NS_ASSUME_NONNULL_END
+22
View File
@@ -0,0 +1,22 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_session.h"
#import "cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTSessionOptions ()
- (Ort::SessionOptions&)CXXAPIOrtSessionOptions;
@end
@interface ORTRunOptions ()
- (Ort::RunOptions&)CXXAPIOrtRunOptions;
@end
NS_ASSUME_NONNULL_END
+160
View File
@@ -0,0 +1,160 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_value_internal.h"
#include <optional>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
NS_ASSUME_NONNULL_BEGIN
namespace {
ORTTensorTypeAndShapeInfo* CXXAPIToPublicTensorTypeAndShapeInfo(
const Ort::ConstTensorTypeAndShapeInfo& CXXAPITensorTypeAndShapeInfo) {
auto* result = [[ORTTensorTypeAndShapeInfo alloc] init];
const auto elementType = CXXAPITensorTypeAndShapeInfo.GetElementType();
const std::vector<int64_t> shape = CXXAPITensorTypeAndShapeInfo.GetShape();
result.elementType = CAPIToPublicTensorElementType(elementType);
auto* shapeArray = [[NSMutableArray alloc] initWithCapacity:shape.size()];
for (size_t i = 0; i < shape.size(); ++i) {
shapeArray[i] = @(shape[i]);
}
result.shape = shapeArray;
return result;
}
ORTValueTypeInfo* CXXAPIToPublicValueTypeInfo(
const Ort::TypeInfo& CXXAPITypeInfo) {
auto* result = [[ORTValueTypeInfo alloc] init];
const auto valueType = CXXAPITypeInfo.GetONNXType();
result.type = CAPIToPublicValueType(valueType);
if (valueType == ONNX_TYPE_TENSOR) {
const auto tensorTypeAndShapeInfo = CXXAPITypeInfo.GetTensorTypeAndShapeInfo();
result.tensorTypeAndShapeInfo = CXXAPIToPublicTensorTypeAndShapeInfo(tensorTypeAndShapeInfo);
}
return result;
}
// out = a * b
// returns true iff the result does not overflow
bool SafeMultiply(size_t a, size_t b, size_t& out) {
return !__builtin_mul_overflow(a, b, &out);
}
} // namespace
@interface ORTValue ()
// pointer to any external tensor data to keep alive for the lifetime of the ORTValue
@property(nonatomic, nullable) NSMutableData* externalTensorData;
@end
@implementation ORTValue {
std::optional<Ort::Value> _value;
std::optional<Ort::TypeInfo> _typeInfo;
}
#pragma mark - Public
- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData
elementType:(ORTTensorElementDataType)elementType
shape:(NSArray<NSNumber*>*)shape
error:(NSError**)error {
try {
const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
const auto ONNXElementType = PublicToCAPITensorElementType(elementType);
const auto shapeVector = [shape]() {
std::vector<int64_t> result{};
result.reserve(shape.count);
for (NSNumber* dim in shape) {
result.push_back(dim.longLongValue);
}
return result;
}();
Ort::Value ortValue = Ort::Value::CreateTensor(
memoryInfo, tensorData.mutableBytes, tensorData.length,
shapeVector.data(), shapeVector.size(), ONNXElementType);
return [self initWithCAPIOrtValue:ortValue.release()
externalTensorData:tensorData
error:error];
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable ORTValueTypeInfo*)typeInfoWithError:(NSError**)error {
try {
return CXXAPIToPublicValueTypeInfo(*_typeInfo);
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable ORTTensorTypeAndShapeInfo*)tensorTypeAndShapeInfoWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
return CXXAPIToPublicTensorTypeAndShapeInfo(tensorTypeAndShapeInfo);
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount();
const size_t elementSize = SizeOfCAPITensorElementType(tensorTypeAndShapeInfo.GetElementType());
size_t rawDataLength;
if (!SafeMultiply(elementCount, elementSize, rawDataLength)) {
ORT_CXX_API_THROW("failed to compute tensor data length", ORT_RUNTIME_EXCEPTION);
}
void* rawData;
Ort::ThrowOnError(Ort::GetApi().GetTensorMutableData(*_value, &rawData));
return [NSMutableData dataWithBytesNoCopy:rawData
length:rawDataLength
freeWhenDone:NO];
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
#pragma mark - Internal
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
externalTensorData:(nullable NSMutableData*)externalTensorData
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_value = Ort::Value{CAPIOrtValue};
_typeInfo = _value->GetTypeInfo();
_externalTensorData = externalTensorData;
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error);
}
- (Ort::Value&)CXXAPIOrtValue {
return *_value;
}
@end
@implementation ORTValueTypeInfo
@end
@implementation ORTTensorTypeAndShapeInfo
@end
NS_ASSUME_NONNULL_END
+20
View File
@@ -0,0 +1,20 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_value.h"
#import "cxx_api.h"
NS_ASSUME_NONNULL_BEGIN
@interface ORTValue ()
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
externalTensorData:(nullable NSMutableData*)externalTensorData
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
- (Ort::Value&)CXXAPIOrtValue;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_xnnpack_execution_provider.h"
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_session_internal.h"
NS_ASSUME_NONNULL_BEGIN
@implementation ORTXnnpackExecutionProviderOptions
@end
@implementation ORTSessionOptions (ORTSessionOptionsXnnpackEP)
- (BOOL)appendXnnpackExecutionProviderWithOptions:(ORTXnnpackExecutionProviderOptions*)options
error:(NSError**)error {
try {
NSDictionary* provider_options = @{
@"intra_op_num_threads" : [NSString stringWithFormat:@"%d", options.intra_op_num_threads]
};
return [self appendExecutionProvider:@"XNNPACK" providerOptions:provider_options error:error];
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error);
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import XCTest
import Foundation
@testable import OnnxRuntimeBindings
final class SwiftOnnxRuntimeBindingsTests: XCTestCase {
let modelPath: String = Bundle.module.url(forResource: "single_add.basic", withExtension: "ort")!.path
func testGetVersionString() throws {
do {
let version = ORTVersion()
XCTAssertNotNil(version)
} catch let error {
XCTFail(error.localizedDescription)
}
}
func testCreateSession() throws {
do {
let env = try ORTEnv(loggingLevel: ORTLoggingLevel.verbose)
let options = try ORTSessionOptions()
try options.setLogSeverityLevel(ORTLoggingLevel.verbose)
try options.setIntraOpNumThreads(1)
// Create the ORTSession
_ = try ORTSession(env: env, modelPath: modelPath, sessionOptions: options)
} catch let error {
XCTFail(error.localizedDescription)
}
}
func testAppendCoreMLEP() throws {
do {
let env = try ORTEnv(loggingLevel: ORTLoggingLevel.verbose)
let sessionOptions: ORTSessionOptions = try ORTSessionOptions()
let coreMLOptions: ORTCoreMLExecutionProviderOptions = ORTCoreMLExecutionProviderOptions()
coreMLOptions.enableOnSubgraphs = true
try sessionOptions.appendCoreMLExecutionProvider(with: coreMLOptions)
XCTAssertTrue(ORTIsCoreMLExecutionProviderAvailable())
_ = try ORTSession(env: env, modelPath: modelPath, sessionOptions: sessionOptions)
} catch let error {
XCTFail(error.localizedDescription)
}
}
func testAppendXnnpackEP() throws {
do {
let env = try ORTEnv(loggingLevel: ORTLoggingLevel.verbose)
let sessionOptions: ORTSessionOptions = try ORTSessionOptions()
let XnnpackOptions: ORTXnnpackExecutionProviderOptions = ORTXnnpackExecutionProviderOptions()
XnnpackOptions.intra_op_num_threads = 2
try sessionOptions.appendXnnpackExecutionProvider(with: XnnpackOptions)
XCTAssertTrue(ORTIsCoreMLExecutionProviderAvailable())
_ = try ORTSession(env: env, modelPath: modelPath, sessionOptions: sessionOptions)
} catch let error {
XCTFail(error.localizedDescription)
}
}
}