Enable SPM support for Ext and configure pipelines for extensions target testing (#3)
* initial ext files * add a workable version of spm for extensions * update * update pipeline * update pipelines * fix dev/release pipelines for extensions pod * fix dev pipelines for extensions pod * fix release pipelines for extensions pod * fix dev pipelines for extensions pod * adding empty include folder for configuring extensions target path * test * test * test * revert pipeline changes * revert gitignore changes * add ext pod binary target for release pipeline * add pipeline for extensions * update * update package.swift * update latest from branch * update * fix * fix * update * try dummy empty file * test * update package.swift to use fatalerror * syntax * try gitignore revert * update gitignore * add -list * onnxruntime-Package * update using onnxruntime-Package * update dev pipeline * fix dev pipelines * syntax * pull extensions/ * update pipelines again * syntax * variables * fix * fix -r * update Package.swift * update Package.swift * minor update * address pr comments * minor updates * fix * refine messages * syntax * syntax again * address pr comments partial * address pr comments * add .h header file and notes * minor updates * syncing objc source files and add code to register custom ops using function pointer * format * move to the header for function doc --------- Co-authored-by: rachguo <rachguo@rachguos-Mini.attlocal.net> Co-authored-by: rachguo <rachguo@rachguos-Mac-mini.local>
This commit is contained in:
+2
-1
@@ -400,4 +400,5 @@ FodyWeavers.xsd
|
||||
.DS_Store
|
||||
*.DS_Store
|
||||
|
||||
.build/
|
||||
.build/
|
||||
.swiftpm
|
||||
@@ -68,5 +68,5 @@
|
||||
displayName: "Print ORT iOS Pod checksum and Test Package.swift usage"
|
||||
|
||||
- template: templates/component-governance-component-detection-steps.yml
|
||||
parameters :
|
||||
condition : 'succeeded'
|
||||
parameters:
|
||||
condition: 'succeeded'
|
||||
@@ -0,0 +1,102 @@
|
||||
jobs:
|
||||
- job: j
|
||||
displayName: "Test with ORT Extensions native pod"
|
||||
|
||||
pool:
|
||||
vmImage: "macOS-13"
|
||||
|
||||
variables:
|
||||
xcodeVersion: "14.3"
|
||||
artifactsName: "ios_packaging_artifacts_full"
|
||||
artifactsNameForExt: "ios_packaging_artifacts"
|
||||
|
||||
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
|
||||
git checkout
|
||||
workingDirectory: "$(Build.SourcesDirectory)"
|
||||
displayName: "Sparse checkout objectivec/ 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 for ORT C pod from iOS packaging pipeline
|
||||
- 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 for ORT C Pod"
|
||||
|
||||
# Download artifacts for ORT Ext C pod from extensions iOS packaging pipeline
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'specific'
|
||||
project: 'Lotus'
|
||||
definition: 1206 #'definitionid' is obtained from `System.DefinitionId` of extensions CI: extensions.ios_packaging
|
||||
buildVersionToDownload: 'latest'
|
||||
branchName: 'main'
|
||||
targetPath: '$(Build.ArtifactStagingDirectory)'
|
||||
|
||||
- script: |
|
||||
set -e -x
|
||||
ls
|
||||
workingDirectory: '$(Build.ArtifactStagingDirectory)/$(artifactsNameForExt)'
|
||||
displayName: "List staged artifacts for ORT Ext C Pod"
|
||||
|
||||
# Note: Running xcodebuild test on `onnxruntime-Package` scheme will perform swift unit tests for both OnnxRuntimeBindings
|
||||
# and OnnxRuntimeExtensions targets.
|
||||
- script: |
|
||||
set -e -x
|
||||
cd "$(Build.ArtifactStagingDirectory)/$(artifactsName)"
|
||||
POD_ARCHIVE=$(find . -name "pod-archive-onnxruntime-c-*.zip")
|
||||
|
||||
echo "Printing the checksum here to make it easier when updating for actual release pod archive file in Package.swift"
|
||||
shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}"
|
||||
|
||||
cd "$(Build.ArtifactStagingDirectory)/$(artifactsNameForExt)"
|
||||
POD_ARCHIVE_EXT=$(find . -name "pod-archive-onnxruntime-extensions-c-*.zip")
|
||||
|
||||
echo "Printing the checksum here to make it easier when updating for actual release extensions pod archive file in Package.swift"
|
||||
shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsNameForExt)/${POD_ARCHIVE_EXT}"
|
||||
|
||||
cd "$(Build.SourcesDirectory)/tmp/onnxruntime"
|
||||
cp -r "$(Build.SourcesDirectory)/swift" .
|
||||
cp "$(Build.SourcesDirectory)/Package.swift" .
|
||||
cp -r "$(Build.SourcesDirectory)/extensions" .
|
||||
|
||||
cp "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" swift/
|
||||
export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}"
|
||||
cp "$(Build.ArtifactStagingDirectory)/$(artifactsNameForExt)/${POD_ARCHIVE_EXT}" swift/
|
||||
export ORT_EXTENSIONS_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_EXT}"
|
||||
|
||||
xcodebuild test -scheme onnxruntime-Package -destination 'platform=iOS Simulator,name=iPhone 14'
|
||||
|
||||
rm swift/pod-archive-onnxruntime-c-*.zip
|
||||
rm swift/pod-archive-onnxruntime-extensions-c-*.zip
|
||||
workingDirectory: "$(Build.SourcesDirectory)/tmp"
|
||||
displayName: "Test Package.swift usage for ORT and ORT Extensions"
|
||||
|
||||
- template: templates/component-governance-component-detection-steps.yml
|
||||
parameters:
|
||||
condition: 'succeeded'
|
||||
@@ -14,13 +14,40 @@
|
||||
- template: templates/use-xcode-version.yml
|
||||
parameters:
|
||||
xcodeVersion: ${{ variables.xcodeVersion }}
|
||||
|
||||
# Note: Currently it requires a dev version extensions c pod for testing
|
||||
- task: DownloadPipelineArtifact@2
|
||||
inputs:
|
||||
buildType: 'specific'
|
||||
project: 'Lotus'
|
||||
definition: 1206 #'definitionid' is obtained from `System.DefinitionId` of extensions CI: extensions.ios_packaging
|
||||
buildVersionToDownload: 'latest'
|
||||
branchName: 'main'
|
||||
targetPath: '$(Build.ArtifactStagingDirectory)'
|
||||
|
||||
- script: |
|
||||
set -e -x
|
||||
xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14'
|
||||
ls
|
||||
workingDirectory: "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts"
|
||||
displayName: "List staged artifacts for ORT Ext C Pod"
|
||||
|
||||
# Note: Running xcodebuild test on `onnxruntime-Package` scheme will perform swift tests for both OnnxRuntimeBindings
|
||||
# and OnnxRuntimeExtensions targets.
|
||||
- script: |
|
||||
set -e -x
|
||||
|
||||
cd "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts"
|
||||
POD_ARCHIVE=$(find . -name "pod-archive-onnxruntime-extensions-c-*.zip")
|
||||
|
||||
cd "$(Build.SourcesDirectory)"
|
||||
cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${POD_ARCHIVE}" swift/
|
||||
export ORT_EXTENSIONS_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}"
|
||||
|
||||
xcodebuild test -scheme onnxruntime-Package -destination 'platform=iOS Simulator,name=iPhone 14'
|
||||
rm swift/pod-archive-onnxruntime-extensions-c-*.zip
|
||||
workingDirectory: "$(Build.SourcesDirectory)"
|
||||
displayName: "Test Package.swift usage"
|
||||
|
||||
- template: templates/component-governance-component-detection-steps.yml
|
||||
parameters :
|
||||
condition : 'succeeded'
|
||||
parameters:
|
||||
condition: 'succeeded'
|
||||
+43
-1
@@ -24,13 +24,23 @@ let package = Package(
|
||||
.library(name: "onnxruntime",
|
||||
type: .static,
|
||||
targets: ["OnnxRuntimeBindings"]),
|
||||
.library(name: "onnxruntime_extensions",
|
||||
type: .static,
|
||||
targets: ["OnnxRuntimeExtensions"]),
|
||||
],
|
||||
dependencies: [],
|
||||
targets: [
|
||||
.target(name: "OnnxRuntimeBindings",
|
||||
dependencies: ["onnxruntime"],
|
||||
path: "objectivec",
|
||||
exclude: ["ReadMe.md", "format_objc.sh"],
|
||||
exclude: ["ReadMe.md", "format_objc.sh", "test",
|
||||
"ort_checkpoint.mm",
|
||||
"ort_checkpoint_internal.h",
|
||||
"ort_training_session_internal.h",
|
||||
"ort_training_session.mm",
|
||||
"include/ort_checkpoint.h",
|
||||
"include/ort_training_session.h",
|
||||
"include/onnxruntime_training.h"],
|
||||
cxxSettings: [
|
||||
.define("SPM_BUILD"),
|
||||
.unsafeFlags(["-std=c++17",
|
||||
@@ -45,6 +55,23 @@ let package = Package(
|
||||
resources: [
|
||||
.copy("Resources/single_add.basic.ort")
|
||||
]),
|
||||
.target(name: "OnnxRuntimeExtensions",
|
||||
dependencies: ["onnxruntime_extensions", "onnxruntime"],
|
||||
path: "extensions",
|
||||
cxxSettings: [
|
||||
.define("ORT_SWIFT_PACKAGE_MANAGER_BUILD"),
|
||||
.unsafeFlags(["-std=c++17",
|
||||
"-fobjc-arc-exceptions"
|
||||
]),
|
||||
], linkerSettings: [
|
||||
.unsafeFlags(["-ObjC"]),
|
||||
]),
|
||||
.testTarget(name: "OnnxRuntimeExtensionsTests",
|
||||
dependencies: ["OnnxRuntimeExtensions", "OnnxRuntimeBindings"],
|
||||
path: "swift/OnnxRuntimeExtensionsTests",
|
||||
resources: [
|
||||
.copy("Resources/decode_image.onnx")
|
||||
]),
|
||||
]
|
||||
)
|
||||
|
||||
@@ -83,3 +110,18 @@ if let pod_archive_path = ProcessInfo.processInfo.environment["ORT_IOS_POD_LOCAL
|
||||
checksum: "9b41412329a73d7d298b1d94ab40ae9adb65cb84f132054073bc82515b4f5f82")
|
||||
)
|
||||
}
|
||||
|
||||
if let ext_pod_archive_path = ProcessInfo.processInfo.environment["ORT_EXTENSIONS_IOS_POD_LOCAL_PATH"] {
|
||||
package.targets.append(Target.binaryTarget(name: "onnxruntime_extensions", path: ext_pod_archive_path))
|
||||
}
|
||||
// Note: ORT Extensions 0.8.0 release version pod (Currently not working - it gives a header path not found error.)
|
||||
else {
|
||||
// package.targets.append(
|
||||
// Target.binaryTarget(name: "onnxruntime_extensions",
|
||||
// url: "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-extensions-c-0.8.0.zip",
|
||||
// checksum: "1d003770c9a6d0ead92c04ed40d5083e8f4f55ea985750c3efab91489be15512")
|
||||
// )
|
||||
fatalError("It is not valid to use a release version extensions c pod for now.\n" +
|
||||
"Please set ORT_EXTENSIONS_IOS_POD_LOCAL_PATH environment variable to specify a location for local dev version pod.\n" +
|
||||
"See Package.swift for more information on using a local pod archive.")
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "OrtExt.h"
|
||||
|
||||
#include "onnxruntime_extensions/onnxruntime_extensions.h"
|
||||
|
||||
@implementation OrtExt
|
||||
|
||||
+ (nonnull ORTCAPIRegisterCustomOpsFnPtr)getRegisterCustomOpsFunctionPointer {
|
||||
return RegisterCustomOps;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,3 @@
|
||||
// This is the umbrella header
|
||||
|
||||
#include "OrtExt.h"
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface OrtExt : NSObject
|
||||
|
||||
typedef struct OrtStatus* (*ORTCAPIRegisterCustomOpsFnPtr)(struct OrtSessionOptions* /*options*/,
|
||||
const struct OrtApiBase* /*api*/);
|
||||
|
||||
// Note: This returns the address of `RegisterCustomOps` function. At swift
|
||||
// level, user can call this function to get the RegisterCustomOpsFnPtr
|
||||
// and use the function pointer to register custom ops. See
|
||||
// SwiftOnnxRuntimeExtensionsTests.swift for an example usage.
|
||||
+ (nonnull ORTCAPIRegisterCustomOpsFnPtr)getRegisterCustomOpsFunctionPointer;
|
||||
|
||||
@end
|
||||
+15
-16
@@ -11,29 +11,28 @@
|
||||
#endif // defined(__clang__)
|
||||
|
||||
// paths are different when building the Swift Package Manager package as the headers come from the iOS pod archive
|
||||
// clang-format off
|
||||
#define STRINGIFY(x) #x
|
||||
#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"
|
||||
#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(onnxruntime/x)
|
||||
#else
|
||||
#define ORT_OBJC_API_COREML_EP_AVAILABLE 0
|
||||
#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(x)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_c_api.h))
|
||||
#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_c_api.h)
|
||||
#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_training_cxx_api.h)
|
||||
#else
|
||||
#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_c_api.h)
|
||||
#include ORT_C_CXX_HEADER_FILE_PATH(onnxruntime_cxx_api.h)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include "onnxruntime_c_api.h"
|
||||
#include "onnxruntime_cxx_api.h"
|
||||
|
||||
#if __has_include("coreml_provider_factory.h")
|
||||
#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h))
|
||||
#define ORT_OBJC_API_COREML_EP_AVAILABLE 1
|
||||
#include "coreml_provider_factory.h"
|
||||
#include ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h)
|
||||
#else
|
||||
#define ORT_OBJC_API_COREML_EP_AVAILABLE 0
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#import "cxx_api.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@class ORTValue;
|
||||
|
||||
namespace utils {
|
||||
|
||||
NSString* toNSString(const std::string& str);
|
||||
NSString* _Nullable toNullableNSString(const std::optional<std::string>& str);
|
||||
|
||||
std::string toStdString(NSString* str);
|
||||
std::optional<std::string> toStdOptionalString(NSString* _Nullable str);
|
||||
|
||||
std::vector<std::string> toStdStringVector(NSArray<NSString*>* strs);
|
||||
NSArray<NSString*>* toNSStringNSArray(const std::vector<std::string>& strs);
|
||||
|
||||
NSArray<ORTValue*>* _Nullable wrapUnownedCAPIOrtValues(const std::vector<OrtValue*>& values, NSError** error);
|
||||
|
||||
std::vector<const OrtValue*> getWrappedCAPIOrtValues(NSArray<ORTValue*>* values);
|
||||
|
||||
} // namespace utils
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "cxx_utils.h"
|
||||
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#import "error_utils.h"
|
||||
|
||||
#import "ort_value_internal.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
namespace utils {
|
||||
|
||||
NSString* toNSString(const std::string& str) {
|
||||
NSString* nsStr = [NSString stringWithUTF8String:str.c_str()];
|
||||
if (!nsStr) {
|
||||
ORT_CXX_API_THROW("Failed to convert std::string to NSString", ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
return nsStr;
|
||||
}
|
||||
|
||||
NSString* _Nullable toNullableNSString(const std::optional<std::string>& str) {
|
||||
if (str.has_value()) {
|
||||
return toNSString(*str);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
std::string toStdString(NSString* str) {
|
||||
return std::string([str UTF8String]);
|
||||
}
|
||||
|
||||
std::optional<std::string> toStdOptionalString(NSString* _Nullable str) {
|
||||
if (str) {
|
||||
return std::optional<std::string>([str UTF8String]);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<std::string> toStdStringVector(NSArray<NSString*>* strs) {
|
||||
std::vector<std::string> result;
|
||||
result.reserve(strs.count);
|
||||
for (NSString* str in strs) {
|
||||
result.push_back([str UTF8String]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NSArray<NSString*>* toNSStringNSArray(const std::vector<std::string>& strs) {
|
||||
NSMutableArray<NSString*>* result = [NSMutableArray arrayWithCapacity:strs.size()];
|
||||
for (const std::string& str : strs) {
|
||||
[result addObject:toNSString(str)];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
NSArray<ORTValue*>* _Nullable wrapUnownedCAPIOrtValues(const std::vector<OrtValue*>& CAPIValues, NSError** error) {
|
||||
NSMutableArray<ORTValue*>* result = [NSMutableArray arrayWithCapacity:CAPIValues.size()];
|
||||
for (size_t i = 0; i < CAPIValues.size(); ++i) {
|
||||
// Wrap the C OrtValue in a C++ Ort::Value to automatically handle its release.
|
||||
// Then, transfer that C++ Ort::Value to a new ORTValue.
|
||||
Ort::Value CXXAPIValue{CAPIValues[i]};
|
||||
ORTValue* val = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(CXXAPIValue)
|
||||
externalTensorData:nil
|
||||
error:error];
|
||||
if (!val) {
|
||||
// clean up remaining C OrtValues which haven't been wrapped by a C++ Ort::Value yet
|
||||
for (size_t j = i + 1; j < CAPIValues.size(); ++j) {
|
||||
Ort::GetApi().ReleaseValue(CAPIValues[j]);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
[result addObject:val];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<const OrtValue*> getWrappedCAPIOrtValues(NSArray<ORTValue*>* values) {
|
||||
std::vector<const OrtValue*> result;
|
||||
result.reserve(values.count);
|
||||
for (ORTValue* val in values) {
|
||||
result.push_back(static_cast<const OrtValue*>([val CXXAPIOrtValue]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace utils
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -10,6 +10,7 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
void ORTSaveCodeAndDescriptionToError(int code, const char* description, NSError** error);
|
||||
void ORTSaveCodeAndDescriptionToError(int code, NSString* description, NSError** error);
|
||||
void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error);
|
||||
void ORTSaveExceptionToError(const std::exception& e, NSError** error);
|
||||
|
||||
|
||||
@@ -18,6 +18,14 @@ void ORTSaveCodeAndDescriptionToError(int code, const char* descriptionCstr, NSE
|
||||
userInfo:@{NSLocalizedDescriptionKey : description}];
|
||||
}
|
||||
|
||||
void ORTSaveCodeAndDescriptionToError(int code, NSString* description, NSError** error) {
|
||||
if (!error) return;
|
||||
|
||||
*error = [NSError errorWithDomain:kOrtErrorDomain
|
||||
code:code
|
||||
userInfo:@{NSLocalizedDescriptionKey : description}];
|
||||
}
|
||||
|
||||
void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error) {
|
||||
ORTSaveCodeAndDescriptionToError(e.GetOrtErrorCode(), e.what(), error);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
// the headers below can also be imported individually
|
||||
|
||||
#import "ort_coreml_execution_provider.h"
|
||||
#import "ort_xnnpack_execution_provider.h"
|
||||
#import "ort_custom_op_registration.h"
|
||||
#import "ort_enums.h"
|
||||
#import "ort_env.h"
|
||||
#import "ort_session.h"
|
||||
#import "ort_value.h"
|
||||
#import "ort_xnnpack_execution_provider.h"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
// this header contains the entire ONNX Runtime training Objective-C API
|
||||
// the headers below can also be imported individually
|
||||
|
||||
#import "onnxruntime.h"
|
||||
#import "ort_checkpoint.h"
|
||||
#import "ort_training_session.h"
|
||||
@@ -0,0 +1,119 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <stdint.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* An ORT checkpoint is a snapshot of the state of a model at a given point in time.
|
||||
*
|
||||
* This class holds the entire training session state that includes model parameters,
|
||||
* their gradients, optimizer parameters, and user properties. The `ORTTrainingSession` leverages the
|
||||
* `ORTCheckpoint` by accessing and updating the contained training state.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* @note This class is only available when the training APIs are enabled.
|
||||
*/
|
||||
@interface ORTCheckpoint : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Creates a checkpoint from directory on disk.
|
||||
*
|
||||
* @param path The path to the checkpoint directory.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The instance, or nil if an error occurs.
|
||||
*
|
||||
* @warning The construction of the checkpoint state requires instantiation of `ORTEnv`.
|
||||
* The intialization will fail if the `ORTEnv` is not properly initialized.
|
||||
*/
|
||||
- (nullable instancetype)initWithPath:(NSString*)path
|
||||
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Saves a checkpoint to directory on disk.
|
||||
*
|
||||
* @param path The path to the checkpoint directory.
|
||||
* @param includeOptimizerState Flag to indicate whether to save the optimizer state or not.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the checkpoint was saved successfully.
|
||||
*/
|
||||
- (BOOL)saveCheckpointToPath:(NSString*)path
|
||||
withOptimizerState:(BOOL)includeOptimizerState
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Adds an int property to this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param value The value of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the property was added successfully.
|
||||
*/
|
||||
- (BOOL)addIntPropertyWithName:(NSString*)name
|
||||
value:(int64_t)value
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Adds a float property to this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param value The value of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the property was added successfully.
|
||||
*/
|
||||
- (BOOL)addFloatPropertyWithName:(NSString*)name
|
||||
value:(float)value
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Adds a string property to this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param value The value of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the property was added successfully.
|
||||
*/
|
||||
|
||||
- (BOOL)addStringPropertyWithName:(NSString*)name
|
||||
value:(NSString*)value
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Gets an int property from this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The value of the property or 0 if an error occurs.
|
||||
*/
|
||||
- (int64_t)getIntPropertyWithName:(NSString*)name
|
||||
error:(NSError**)error __attribute__((swift_error(nonnull_error)));
|
||||
|
||||
/**
|
||||
* Gets a float property from this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The value of the property or 0.0f if an error occurs.
|
||||
*/
|
||||
- (float)getFloatPropertyWithName:(NSString*)name
|
||||
error:(NSError**)error __attribute__((swift_error(nonnull_error)));
|
||||
|
||||
/**
|
||||
*
|
||||
* Gets a string property from this checkpoint.
|
||||
*
|
||||
* @param name The name of the property.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The value of the property.
|
||||
*/
|
||||
- (nullable NSString*)getStringPropertyWithName:(NSString*)name
|
||||
error:(NSError**)error __attribute__((swift_error(nonnull_error)));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/** C API type forward declaration. */
|
||||
struct OrtStatus;
|
||||
|
||||
/** C API type forward declaration. */
|
||||
struct OrtApiBase;
|
||||
|
||||
/** C API type forward declaration. */
|
||||
struct OrtSessionOptions;
|
||||
|
||||
/**
|
||||
* Pointer to a custom op registration function that uses the ONNX Runtime C API.
|
||||
*
|
||||
* The signature is defined in the ONNX Runtime C API:
|
||||
* https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697
|
||||
*
|
||||
* This is a low-level type intended for interoperating with libraries which provide such a function for custom op
|
||||
* registration, such as [ONNX Runtime Extensions](https://github.com/microsoft/onnxruntime-extensions).
|
||||
*/
|
||||
typedef struct OrtStatus* (*ORTCAPIRegisterCustomOpsFnPtr)(struct OrtSessionOptions* /*options*/,
|
||||
const struct OrtApiBase* /*api*/);
|
||||
@@ -38,12 +38,13 @@ typedef NS_ENUM(int32_t, ORTTensorElementDataType) {
|
||||
ORTTensorElementDataTypeUInt32,
|
||||
ORTTensorElementDataTypeInt64,
|
||||
ORTTensorElementDataTypeUInt64,
|
||||
ORTTensorElementDataTypeString,
|
||||
};
|
||||
|
||||
/**
|
||||
* The ORT graph optimization levels.
|
||||
* See here for more details:
|
||||
* https://onnxruntime.ai/docs/performance/graph-optimizations.html
|
||||
* https://onnxruntime.ai/docs/performance/model-optimizations/graph-optimizations.html
|
||||
*/
|
||||
typedef NS_ENUM(int32_t, ORTGraphOptimizationLevel) {
|
||||
ORTGraphOptimizationLevelNone,
|
||||
|
||||
@@ -16,7 +16,7 @@ extern "C" {
|
||||
*
|
||||
* Available since 1.15.
|
||||
*/
|
||||
NSString* ORTVersion(void);
|
||||
NSString* _Nullable ORTVersion(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "ort_custom_op_registration.h"
|
||||
#import "ort_enums.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
@@ -196,12 +197,19 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
* Available since 1.14.
|
||||
*
|
||||
* The registration function must have the signature:
|
||||
* OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);
|
||||
* `OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);`
|
||||
*
|
||||
* The signature is defined in the ONNX Runtime C API:
|
||||
* https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @note The caller must ensure that `registrationFuncName` names a valid function that is visible to the native ONNX
|
||||
* Runtime code and has the correct signature.
|
||||
* They must ensure that the function does what they expect it to do because this method will just call it.
|
||||
*
|
||||
* @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.
|
||||
@@ -209,6 +217,46 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Registers custom ops for use with `ORTSession`s using this SessionOptions by calling the specified function
|
||||
* pointed to by `registerCustomOpsFn`.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* The registration function must have the signature:
|
||||
* `OrtStatus* (*fn)(OrtSessionOptions* options, const OrtApiBase* api);`
|
||||
*
|
||||
* The signature is defined in the ONNX Runtime C API:
|
||||
* https://github.com/microsoft/onnxruntime/blob/67f4cd54fab321d83e4a75a40efeee95a6a17079/include/onnxruntime/core/session/onnxruntime_c_api.h#L697
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @note The caller must ensure that `registerCustomOpsFn` is a valid function pointer and has the correct signature.
|
||||
* They must ensure that the function does what they expect it to do because this method will just call it.
|
||||
*
|
||||
* @param registerCustomOpsFn A pointer to the registration function to call.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the registration function was successfully called.
|
||||
*/
|
||||
- (BOOL)registerCustomOpsUsingFunctionPointer:(ORTCAPIRegisterCustomOpsFnPtr)registerCustomOpsFn
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Registers ONNX Runtime Extensions custom ops that have been built in to ONNX Runtime.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* @note ONNX Runtime must have been built with the `--use_extensions` flag for the ONNX Runtime Extensions custom ops
|
||||
* to be able to be registered with this method. When using a separate ONNX Runtime Extensions library, use
|
||||
* `registerCustomOpsUsingFunctionPointer:error:` instead.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return Whether the ONNX Runtime Extensions custom ops were successfully registered.
|
||||
*/
|
||||
- (BOOL)enableOrtExtensionsCustomOpsWithError:(NSError**)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <stdint.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class ORTCheckpoint;
|
||||
@class ORTEnv;
|
||||
@class ORTValue;
|
||||
@class ORTSessionOptions;
|
||||
|
||||
/**
|
||||
* Trainer class that provides methods to train, evaluate and optimize ONNX models.
|
||||
*
|
||||
* The training session requires four training artifacts:
|
||||
* 1. Training onnx model
|
||||
* 2. Evaluation onnx model (optional)
|
||||
* 3. Optimizer onnx model
|
||||
* 4. Checkpoint directory
|
||||
*
|
||||
* [onnxruntime-training python utility](https://github.com/microsoft/onnxruntime/blob/main/orttraining/orttraining/python/training/onnxblock/README.md)
|
||||
* can be used to generate above training artifacts.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* @note This class is only available when the training APIs are enabled.
|
||||
*/
|
||||
@interface ORTTrainingSession : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
/**
|
||||
* Creates a training session from the training artifacts that can be used to begin or resume training.
|
||||
*
|
||||
* The initializer instantiates the training session based on provided env and session options, which can be used to
|
||||
* begin or resume training from a given checkpoint state. The checkpoint state represents the parameters of training
|
||||
* session which will be moved to the device specified in the session option if needed.
|
||||
*
|
||||
* @param env The `ORTEnv` instance to use for the training session.
|
||||
* @param sessionOptions The `ORTSessionOptions` to use for the training session.
|
||||
* @param checkpoint Training states that are used as a starting point for training.
|
||||
* @param trainModelPath The path to the training onnx model.
|
||||
* @param evalModelPath The path to the evaluation onnx model.
|
||||
* @param optimizerModelPath The path to the optimizer onnx model used to perform gradient descent.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The instance, or nil if an error occurs.
|
||||
*
|
||||
* @note Note that the training session created with a checkpoint state uses this state to store the entire training
|
||||
* state (including model parameters, its gradients, the optimizer states and the properties). The training session
|
||||
* keeps a strong (owning) pointer to the checkpoint state.
|
||||
*/
|
||||
- (nullable instancetype)initWithEnv:(ORTEnv*)env
|
||||
sessionOptions:(ORTSessionOptions*)sessionOptions
|
||||
checkpoint:(ORTCheckpoint*)checkpoint
|
||||
trainModelPath:(NSString*)trainModelPath
|
||||
evalModelPath:(nullable NSString*)evalModelPath
|
||||
optimizerModelPath:(nullable NSString*)optimizerModelPath
|
||||
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Performs a training step, which is equivalent to a forward and backward propagation in a single step.
|
||||
*
|
||||
* The training step computes the outputs of the training model and the gradients of the trainable parameters
|
||||
* for the given input values. The train step is performed based on the training model that was provided to the training session.
|
||||
* It is equivalent to running forward and backward propagation in a single step. The computed gradients are stored inside
|
||||
* the training session state so they can be later consumed by `optimizerStep`. The gradients can be lazily reset by
|
||||
* calling `lazyResetGrad` method.
|
||||
*
|
||||
* @param inputs The input values to the training model.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The output values of the training model.
|
||||
*/
|
||||
- (nullable NSArray<ORTValue*>*)trainStepWithInputValues:(NSArray<ORTValue*>*)inputs
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Performs a evaluation step that computes the outputs of the evaluation model for the given inputs.
|
||||
* The eval step is performed based on the evaluation model that was provided to the training session.
|
||||
*
|
||||
* @param inputs The input values to the eval model.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The output values of the eval model.
|
||||
*
|
||||
*/
|
||||
- (nullable NSArray<ORTValue*>*)evalStepWithInputValues:(NSArray<ORTValue*>*)inputs
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Reset the gradients of all trainable parameters to zero lazily.
|
||||
*
|
||||
* Calling this method sets the internal state of the training session such that the gradients of the trainable parameters
|
||||
* in the ORTCheckpoint will be scheduled to be reset just before the new gradients are computed on the next
|
||||
* invocation of the `trainStep` method.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the gradients are set to reset successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)lazyResetGradWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Performs the weight updates for the trainable parameters using the optimizer model. The optimizer step is performed
|
||||
* based on the optimizer model that was provided to the training session. The updated parameters are stored inside the
|
||||
* training state so that they can be used by the next `trainStep` method call.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the optimizer step was performed successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)optimizerStepWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns the names of the user inputs for the training model that can be associated with
|
||||
* the `ORTValue` provided to the `trainStep`.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The names of the user inputs for the training model.
|
||||
*/
|
||||
- (nullable NSArray<NSString*>*)getTrainInputNamesWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns the names of the user inputs for the evaluation model that can be associated with
|
||||
* the `ORTValue` provided to the `evalStep`.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The names of the user inputs for the evaluation model.
|
||||
*/
|
||||
- (nullable NSArray<NSString*>*)getEvalInputNamesWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns the names of the user outputs for the training model that can be associated with
|
||||
* the `ORTValue` returned by the `trainStep`.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The names of the user outputs for the training model.
|
||||
*/
|
||||
- (nullable NSArray<NSString*>*)getTrainOutputNamesWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns the names of the user outputs for the evaluation model that can be associated with
|
||||
* the `ORTValue` returned by the `evalStep`.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The names of the user outputs for the evaluation model.
|
||||
*/
|
||||
- (nullable NSArray<NSString*>*)getEvalOutputNamesWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Registers a linear learning rate scheduler for the training session.
|
||||
*
|
||||
* The scheduler gradually decreases the learning rate from the initial value to zero over the course of the training.
|
||||
* The decrease is performed by multiplying the current learning rate by a linearly updated factor.
|
||||
* Before the decrease, the learning rate is gradually increased from zero to the initial value during a warmup phase.
|
||||
*
|
||||
* @param warmupStepCount The number of steps to perform the linear warmup.
|
||||
* @param totalStepCount The total number of steps to perform the linear decay.
|
||||
* @param initialLr The initial learning rate.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the scheduler was registered successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)registerLinearLRSchedulerWithWarmupStepCount:(int64_t)warmupStepCount
|
||||
totalStepCount:(int64_t)totalStepCount
|
||||
initialLr:(float)initialLr
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Update the learning rate based on the registered learning rate scheduler.
|
||||
*
|
||||
* Performs a scheduler step that updates the learning rate that is being used by the training session.
|
||||
* This function should typically be called before invoking the optimizer step for each round, or as necessary
|
||||
* to update the learning rate being used by the training session.
|
||||
*
|
||||
* @note A valid predefined learning rate scheduler must be first registered to invoke this method.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the scheduler step was performed successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)schedulerStepWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns the current learning rate being used by the training session.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The current learning rate or 0.0f if an error occurs.
|
||||
*/
|
||||
- (float)getLearningRateWithError:(NSError**)error __attribute__((swift_error(nonnull_error)));
|
||||
|
||||
/**
|
||||
* Sets the learning rate being used by the training session.
|
||||
*
|
||||
* The current learning rate is maintained by the training session and can be overwritten by invoking this method
|
||||
* with the desired learning rate. This function should not be used when a valid learning rate scheduler is registered.
|
||||
* It should be used either to set the learning rate derived from a custom learning rate scheduler or to set a constant
|
||||
* learning rate to be used throughout the training session.
|
||||
*
|
||||
* @note It does not set the initial learning rate that may be needed by the predefined learning rate schedulers.
|
||||
* To set the initial learning rate for learning rate schedulers, use the `registerLinearLRScheduler` method.
|
||||
*
|
||||
* @param lr The learning rate to be used by the training session.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the learning rate was set successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)setLearningRate:(float)lr
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Loads the training session model parameters from a contiguous buffer.
|
||||
*
|
||||
* @param buffer Contiguous buffer to load the parameters from.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the parameters were loaded successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)fromBufferWithValue:(ORTValue*)buffer
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Returns a contiguous buffer that holds a copy of all training state parameters.
|
||||
*
|
||||
* @param onlyTrainable If YES, returns a buffer that holds only the trainable parameters, otherwise returns a buffer
|
||||
* that holds all the parameters.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return A contiguous buffer that holds a copy of all training state parameters.
|
||||
*/
|
||||
- (nullable ORTValue*)toBufferWithTrainable:(BOOL)onlyTrainable
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Exports the training session model that can be used for inference.
|
||||
*
|
||||
* If the training session was provided with an eval model, the training session can generate an inference model if it
|
||||
* knows the inference graph outputs. The input inference graph outputs are used to prune the eval model so that the
|
||||
* inference model's outputs align with the provided outputs. The exported model is saved at the path provided and
|
||||
* can be used for inferencing with `ORTSession`.
|
||||
*
|
||||
* @note The method reloads the eval model from the path provided to the initializer and expects this path to be valid.
|
||||
*
|
||||
* @param inferenceModelPath The path to the serialized the inference model.
|
||||
* @param graphOutputNames The names of the outputs that are needed in the inference model.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return YES if the inference model was exported successfully, NO otherwise.
|
||||
*/
|
||||
- (BOOL)exportModelForInferenceWithOutputPath:(NSString*)inferenceModelPath
|
||||
graphOutputNames:(NSArray<NSString*>*)graphOutputNames
|
||||
error:(NSError**)error;
|
||||
@end
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This function sets the seed for generating random numbers.
|
||||
* Use this function to generate reproducible results. It should be noted that completely reproducible results are not guaranteed.
|
||||
*
|
||||
* @param seed Manually set seed to use for random number generation.
|
||||
*/
|
||||
void ORTSetSeed(int64_t seed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -32,6 +32,21 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
shape:(NSArray<NSNumber*>*)shape
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Creates a value that is a string tensor.
|
||||
* The string data will be copied into a buffer owned by this ORTValue instance.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* @param tensorStringData The tensor string data.
|
||||
* @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)initWithTensorStringData:(NSArray<NSString*>*)tensorStringData
|
||||
shape:(NSArray<NSNumber*>*)shape
|
||||
error:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Gets the type information.
|
||||
*
|
||||
@@ -63,6 +78,19 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error;
|
||||
|
||||
/**
|
||||
* Gets the tensor string data.
|
||||
* This assumes that the value is a string tensor.
|
||||
*
|
||||
* This returns a copy of the value's underlying string data.
|
||||
*
|
||||
* Available since 1.16.
|
||||
*
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The copy of the tensor string data, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable NSArray<NSString*>*)tensorStringDataWithError:(NSError**)error;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "ort_checkpoint_internal.h"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#import "cxx_api.h"
|
||||
|
||||
#import "error_utils.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation ORTCheckpoint {
|
||||
std::optional<Ort::CheckpointState> _checkpoint;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithPath:(NSString*)path
|
||||
error:(NSError**)error {
|
||||
if ((self = [super init]) == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
try {
|
||||
_checkpoint = Ort::CheckpointState::LoadCheckpoint(path.UTF8String);
|
||||
return self;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (BOOL)saveCheckpointToPath:(NSString*)path
|
||||
withOptimizerState:(BOOL)includeOptimizerState
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
Ort::CheckpointState::SaveCheckpoint([self CXXAPIOrtCheckpoint], path.UTF8String, includeOptimizerState);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)addIntPropertyWithName:(NSString*)name
|
||||
value:(int64_t)value
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)addFloatPropertyWithName:(NSString*)name
|
||||
value:(float)value
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)addStringPropertyWithName:(NSString*)name
|
||||
value:(NSString*)value
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtCheckpoint].AddProperty(name.UTF8String, value.UTF8String);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (nullable NSString*)getStringPropertyWithName:(NSString*)name error:(NSError**)error {
|
||||
try {
|
||||
Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String);
|
||||
if (std::string* str = std::get_if<std::string>(&value)) {
|
||||
return [NSString stringWithUTF8String:str->c_str()];
|
||||
}
|
||||
ORT_CXX_API_THROW("Property is not a string.", ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (int64_t)getIntPropertyWithName:(NSString*)name error:(NSError**)error {
|
||||
try {
|
||||
Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String);
|
||||
if (int64_t* i = std::get_if<int64_t>(&value)) {
|
||||
return *i;
|
||||
}
|
||||
ORT_CXX_API_THROW("Property is not an integer.", ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH(error, 0)
|
||||
}
|
||||
|
||||
- (float)getFloatPropertyWithName:(NSString*)name error:(NSError**)error {
|
||||
try {
|
||||
Ort::Property value = [self CXXAPIOrtCheckpoint].GetProperty(name.UTF8String);
|
||||
if (float* f = std::get_if<float>(&value)) {
|
||||
return *f;
|
||||
}
|
||||
ORT_CXX_API_THROW("Property is not a float.", ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH(error, 0.0f)
|
||||
}
|
||||
|
||||
- (Ort::CheckpointState&)CXXAPIOrtCheckpoint {
|
||||
return *_checkpoint;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "ort_checkpoint.h"
|
||||
|
||||
#import "cxx_api.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ORTCheckpoint ()
|
||||
|
||||
- (Ort::CheckpointState&)CXXAPIOrtCheckpoint;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -4,6 +4,7 @@
|
||||
#import "ort_enums_internal.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
|
||||
#import "cxx_api.h"
|
||||
|
||||
@@ -39,13 +40,13 @@ constexpr ValueTypeInfo kValueTypeInfos[]{
|
||||
struct TensorElementTypeInfo {
|
||||
ORTTensorElementDataType type;
|
||||
ONNXTensorElementDataType capi_type;
|
||||
size_t element_size;
|
||||
std::optional<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},
|
||||
{ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, std::nullopt},
|
||||
{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)},
|
||||
@@ -53,6 +54,7 @@ constexpr TensorElementTypeInfo kElementTypeInfos[]{
|
||||
{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)},
|
||||
{ORTTensorElementDataTypeString, ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING, std::nullopt},
|
||||
};
|
||||
|
||||
struct GraphOptimizationLevelInfo {
|
||||
@@ -119,9 +121,11 @@ ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType
|
||||
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");
|
||||
[capi_type](const auto& type_info) {
|
||||
return type_info.element_size.has_value() && type_info.capi_type == capi_type;
|
||||
},
|
||||
[](const auto& type_info) { return *type_info.element_size; },
|
||||
"unsupported tensor element type or tensor element type does not have a known size");
|
||||
}
|
||||
|
||||
GraphOptimizationLevel PublicToCAPIGraphOptimizationLevel(ORTGraphOptimizationLevel opt_level) {
|
||||
|
||||
@@ -12,9 +12,8 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString* ORTVersion(void) {
|
||||
std::string result = OrtGetApiBase()->GetVersionString();
|
||||
return [NSString stringWithUTF8String:result.c_str()];
|
||||
NSString* _Nullable ORTVersion(void) {
|
||||
return [NSString stringWithUTF8String:OrtGetApiBase()->GetVersionString()];
|
||||
}
|
||||
|
||||
@implementation ORTEnv {
|
||||
|
||||
+50
-16
@@ -66,22 +66,26 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
}
|
||||
|
||||
std::vector<const char*> inputNames, outputNames;
|
||||
std::vector<const OrtValue*> inputValues;
|
||||
std::vector<OrtValue*> outputValues;
|
||||
std::vector<const OrtValue*> inputCAPIValues;
|
||||
std::vector<OrtValue*> outputCAPIValues;
|
||||
|
||||
inputNames.reserve(inputs.count);
|
||||
inputCAPIValues.reserve(inputs.count);
|
||||
for (NSString* inputName in inputs) {
|
||||
inputNames.push_back(inputName.UTF8String);
|
||||
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
|
||||
inputCAPIValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
|
||||
}
|
||||
|
||||
outputNames.reserve(outputs.count);
|
||||
outputCAPIValues.reserve(outputs.count);
|
||||
for (NSString* outputName in outputs) {
|
||||
outputNames.push_back(outputName.UTF8String);
|
||||
outputValues.push_back(static_cast<OrtValue*>([outputs[outputName] CXXAPIOrtValue]));
|
||||
outputCAPIValues.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()));
|
||||
inputNames.data(), inputCAPIValues.data(), inputNames.size(),
|
||||
outputNames.data(), outputNames.size(), outputCAPIValues.data()));
|
||||
|
||||
return YES;
|
||||
}
|
||||
@@ -103,30 +107,39 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
NSArray<NSString*>* outputNameArray = outputNameSet.allObjects;
|
||||
|
||||
std::vector<const char*> inputNames, outputNames;
|
||||
std::vector<const OrtValue*> inputValues;
|
||||
std::vector<OrtValue*> outputValues;
|
||||
std::vector<const OrtValue*> inputCAPIValues;
|
||||
std::vector<OrtValue*> outputCAPIValues;
|
||||
|
||||
inputNames.reserve(inputs.count);
|
||||
inputCAPIValues.reserve(inputs.count);
|
||||
for (NSString* inputName in inputs) {
|
||||
inputNames.push_back(inputName.UTF8String);
|
||||
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
|
||||
inputCAPIValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
|
||||
}
|
||||
|
||||
outputNames.reserve(outputNameArray.count);
|
||||
outputCAPIValues.reserve(outputNameArray.count);
|
||||
for (NSString* outputName in outputNameArray) {
|
||||
outputNames.push_back(outputName.UTF8String);
|
||||
outputValues.push_back(nullptr);
|
||||
outputCAPIValues.push_back(nullptr);
|
||||
}
|
||||
|
||||
Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions],
|
||||
inputNames.data(), inputValues.data(), inputNames.size(),
|
||||
outputNames.data(), outputNames.size(), outputValues.data()));
|
||||
inputNames.data(), inputCAPIValues.data(), inputNames.size(),
|
||||
outputNames.data(), outputNames.size(), outputCAPIValues.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];
|
||||
// Wrap the C OrtValue in a C++ Ort::Value to automatically handle its release.
|
||||
// Then, transfer that C++ Ort::Value to a new ORTValue.
|
||||
Ort::Value outputCXXAPIValue{outputCAPIValues[i]};
|
||||
ORTValue* outputValue = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(outputCXXAPIValue)
|
||||
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]);
|
||||
// clean up remaining C OrtValues which haven't been wrapped by a C++ Ort::Value yet
|
||||
for (NSUInteger j = i + 1; j < outputNameArray.count; ++j) {
|
||||
Ort::GetApi().ReleaseValue(outputCAPIValues[j]);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@@ -296,6 +309,27 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)registerCustomOpsUsingFunctionPointer:(ORTCAPIRegisterCustomOpsFnPtr)registerCustomOpsFn
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
if (!registerCustomOpsFn) {
|
||||
ORT_CXX_API_THROW("registerCustomOpsFn must not be null", ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
Ort::ThrowOnError((*registerCustomOpsFn)(static_cast<OrtSessionOptions*>(*_sessionOptions),
|
||||
OrtGetApiBase()));
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)enableOrtExtensionsCustomOpsWithError:(NSError**)error {
|
||||
try {
|
||||
_sessionOptions->EnableOrtCustomOps();
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
#pragma mark - Internal
|
||||
|
||||
- (Ort::SessionOptions&)CXXAPIOrtSessionOptions {
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "ort_training_session_internal.h"
|
||||
|
||||
#import <vector>
|
||||
#import <optional>
|
||||
#import <string>
|
||||
|
||||
#import "cxx_api.h"
|
||||
#import "cxx_utils.h"
|
||||
#import "error_utils.h"
|
||||
#import "ort_checkpoint_internal.h"
|
||||
#import "ort_session_internal.h"
|
||||
#import "ort_enums_internal.h"
|
||||
#import "ort_env_internal.h"
|
||||
#import "ort_value_internal.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@implementation ORTTrainingSession {
|
||||
std::optional<Ort::TrainingSession> _session;
|
||||
ORTCheckpoint* _checkpoint;
|
||||
}
|
||||
|
||||
- (Ort::TrainingSession&)CXXAPIOrtTrainingSession {
|
||||
return *_session;
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithEnv:(ORTEnv*)env
|
||||
sessionOptions:(ORTSessionOptions*)sessionOptions
|
||||
checkpoint:(ORTCheckpoint*)checkpoint
|
||||
trainModelPath:(NSString*)trainModelPath
|
||||
evalModelPath:(nullable NSString*)evalModelPath
|
||||
optimizerModelPath:(nullable NSString*)optimizerModelPath
|
||||
error:(NSError**)error {
|
||||
if ((self = [super init]) == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
try {
|
||||
std::optional<std::string> evalPath = utils::toStdOptionalString(evalModelPath);
|
||||
std::optional<std::string> optimizerPath = utils::toStdOptionalString(optimizerModelPath);
|
||||
|
||||
_checkpoint = checkpoint;
|
||||
_session = Ort::TrainingSession{
|
||||
[env CXXAPIOrtEnv],
|
||||
[sessionOptions CXXAPIOrtSessionOptions],
|
||||
[checkpoint CXXAPIOrtCheckpoint],
|
||||
trainModelPath.UTF8String,
|
||||
evalPath,
|
||||
optimizerPath};
|
||||
return self;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<ORTValue*>*)trainStepWithInputValues:(NSArray<ORTValue*>*)inputs
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
std::vector<const OrtValue*> inputValues = utils::getWrappedCAPIOrtValues(inputs);
|
||||
|
||||
size_t outputCount;
|
||||
Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetTrainingModelOutputCount(*_session, &outputCount));
|
||||
std::vector<OrtValue*> outputValues(outputCount, nullptr);
|
||||
|
||||
Ort::RunOptions runOptions;
|
||||
Ort::ThrowOnError(Ort::GetTrainingApi().TrainStep(
|
||||
*_session,
|
||||
runOptions,
|
||||
inputValues.size(),
|
||||
inputValues.data(),
|
||||
outputValues.size(),
|
||||
outputValues.data()));
|
||||
|
||||
return utils::wrapUnownedCAPIOrtValues(outputValues, error);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
- (nullable NSArray<ORTValue*>*)evalStepWithInputValues:(NSArray<ORTValue*>*)inputs
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
// create vector of OrtValue from NSArray<ORTValue*> with same size as inputValues
|
||||
std::vector<const OrtValue*> inputValues = utils::getWrappedCAPIOrtValues(inputs);
|
||||
|
||||
size_t outputCount;
|
||||
Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetEvalModelOutputCount(*_session, &outputCount));
|
||||
std::vector<OrtValue*> outputValues(outputCount, nullptr);
|
||||
|
||||
Ort::RunOptions runOptions;
|
||||
Ort::ThrowOnError(Ort::GetTrainingApi().EvalStep(
|
||||
*_session,
|
||||
runOptions,
|
||||
inputValues.size(),
|
||||
inputValues.data(),
|
||||
outputValues.size(),
|
||||
outputValues.data()));
|
||||
|
||||
return utils::wrapUnownedCAPIOrtValues(outputValues, error);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (BOOL)lazyResetGradWithError:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].LazyResetGrad();
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)optimizerStepWithError:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].OptimizerStep();
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString*>*)getTrainInputNamesWithError:(NSError**)error {
|
||||
try {
|
||||
std::vector<std::string> inputNames = [self CXXAPIOrtTrainingSession].InputNames(true);
|
||||
return utils::toNSStringNSArray(inputNames);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString*>*)getTrainOutputNamesWithError:(NSError**)error {
|
||||
try {
|
||||
std::vector<std::string> outputNames = [self CXXAPIOrtTrainingSession].OutputNames(true);
|
||||
return utils::toNSStringNSArray(outputNames);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString*>*)getEvalInputNamesWithError:(NSError**)error {
|
||||
try {
|
||||
std::vector<std::string> inputNames = [self CXXAPIOrtTrainingSession].InputNames(false);
|
||||
return utils::toNSStringNSArray(inputNames);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString*>*)getEvalOutputNamesWithError:(NSError**)error {
|
||||
try {
|
||||
std::vector<std::string> outputNames = [self CXXAPIOrtTrainingSession].OutputNames(false);
|
||||
return utils::toNSStringNSArray(outputNames);
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (BOOL)registerLinearLRSchedulerWithWarmupStepCount:(int64_t)warmupStepCount
|
||||
totalStepCount:(int64_t)totalStepCount
|
||||
initialLr:(float)initialLr
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].RegisterLinearLRScheduler(warmupStepCount, totalStepCount, initialLr);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)schedulerStepWithError:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].SchedulerStep();
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (float)getLearningRateWithError:(NSError**)error {
|
||||
try {
|
||||
return [self CXXAPIOrtTrainingSession].GetLearningRate();
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH(error, 0.0f);
|
||||
}
|
||||
|
||||
- (BOOL)setLearningRate:(float)lr
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].SetLearningRate(lr);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (BOOL)fromBufferWithValue:(ORTValue*)buffer
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].FromBuffer([buffer CXXAPIOrtValue]);
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
- (nullable ORTValue*)toBufferWithTrainable:(BOOL)onlyTrainable
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
Ort::Value val = [self CXXAPIOrtTrainingSession].ToBuffer(onlyTrainable);
|
||||
return [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(val)
|
||||
externalTensorData:nil
|
||||
error:error];
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (BOOL)exportModelForInferenceWithOutputPath:(NSString*)inferenceModelPath
|
||||
graphOutputNames:(NSArray<NSString*>*)graphOutputNames
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
[self CXXAPIOrtTrainingSession].ExportModelForInferencing(utils::toStdString(inferenceModelPath),
|
||||
utils::toStdStringVector(graphOutputNames));
|
||||
return YES;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
void ORTSetSeed(int64_t seed) {
|
||||
Ort::SetSeed(seed);
|
||||
}
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#import "ort_training_session.h"
|
||||
|
||||
#import "cxx_api.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ORTTrainingSession ()
|
||||
|
||||
- (Ort::TrainingSession&)CXXAPIOrtTrainingSession;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
+85
-8
@@ -71,6 +71,12 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) {
|
||||
shape:(NSArray<NSNumber*>*)shape
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
if (elementType == ORTTensorElementDataTypeString) {
|
||||
ORT_CXX_API_THROW(
|
||||
"ORTTensorElementDataTypeString element type provided. "
|
||||
"Please call initWithTensorStringData:shape:error: instead to create an ORTValue with string data.",
|
||||
ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
|
||||
const auto ONNXElementType = PublicToCAPITensorElementType(elementType);
|
||||
const auto shapeVector = [shape]() {
|
||||
@@ -85,9 +91,49 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) {
|
||||
memoryInfo, tensorData.mutableBytes, tensorData.length,
|
||||
shapeVector.data(), shapeVector.size(), ONNXElementType);
|
||||
|
||||
return [self initWithCAPIOrtValue:ortValue.release()
|
||||
externalTensorData:tensorData
|
||||
error:error];
|
||||
return [self initWithCXXAPIOrtValue:std::move(ortValue)
|
||||
externalTensorData:tensorData
|
||||
error:error];
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable instancetype)initWithTensorStringData:(NSArray<NSString*>*)tensorStringData
|
||||
shape:(NSArray<NSNumber*>*)shape
|
||||
error:(NSError**)error {
|
||||
try {
|
||||
Ort::AllocatorWithDefaultOptions allocator;
|
||||
size_t tensorSize = 1U;
|
||||
const auto shapeVector = [&tensorSize, shape]() {
|
||||
std::vector<int64_t> result{};
|
||||
result.reserve(shape.count);
|
||||
for (NSNumber* dim in shape) {
|
||||
const auto dimValue = dim.longLongValue;
|
||||
if (dimValue < 0 || !SafeMultiply(static_cast<size_t>(dimValue), tensorSize, tensorSize)) {
|
||||
ORT_CXX_API_THROW("Failed to compute the tensor size.", ORT_RUNTIME_EXCEPTION);
|
||||
}
|
||||
result.push_back(dimValue);
|
||||
}
|
||||
return result;
|
||||
}();
|
||||
|
||||
if (tensorSize != [tensorStringData count]) {
|
||||
ORT_CXX_API_THROW(
|
||||
"Computed tensor size does not equal the length of the provided tensor string data.",
|
||||
ORT_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
Ort::Value ortValue = Ort::Value::CreateTensor(
|
||||
allocator, shapeVector.data(), shapeVector.size(), ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING);
|
||||
|
||||
size_t index = 0;
|
||||
for (NSString* stringData in tensorStringData) {
|
||||
ortValue.FillStringTensorElement([stringData UTF8String], index++);
|
||||
}
|
||||
|
||||
return [self initWithCXXAPIOrtValue:std::move(ortValue)
|
||||
externalTensorData:nil
|
||||
error:error];
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
@@ -110,6 +156,12 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) {
|
||||
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error {
|
||||
try {
|
||||
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
|
||||
if (tensorTypeAndShapeInfo.GetElementType() == ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING) {
|
||||
ORT_CXX_API_THROW(
|
||||
"This ORTValue holds string data. Please call tensorStringDataWithError: "
|
||||
"instead to retrieve the string data from this ORTValue.",
|
||||
ORT_RUNTIME_EXCEPTION);
|
||||
}
|
||||
const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount();
|
||||
const size_t elementSize = SizeOfCAPITensorElementType(tensorTypeAndShapeInfo.GetElementType());
|
||||
size_t rawDataLength;
|
||||
@@ -127,19 +179,44 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) {
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
- (nullable NSArray<NSString*>*)tensorStringDataWithError:(NSError**)error {
|
||||
try {
|
||||
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
|
||||
const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount();
|
||||
const size_t tensorStringDataLength = _value->GetStringTensorDataLength();
|
||||
std::vector<char> tensorStringData(tensorStringDataLength, '\0');
|
||||
std::vector<size_t> offsets(elementCount);
|
||||
_value->GetStringTensorContent(tensorStringData.data(), tensorStringDataLength,
|
||||
offsets.data(), offsets.size());
|
||||
|
||||
NSMutableArray<NSString*>* result = [NSMutableArray arrayWithCapacity:elementCount];
|
||||
for (size_t idx = 0; idx < elementCount; ++idx) {
|
||||
const size_t strLength = (idx == elementCount - 1) ? tensorStringDataLength - offsets[idx]
|
||||
: offsets[idx + 1] - offsets[idx];
|
||||
[result addObject:[[NSString alloc] initWithBytes:tensorStringData.data() + offsets[idx]
|
||||
length:strLength
|
||||
encoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
|
||||
}
|
||||
|
||||
#pragma mark - Internal
|
||||
|
||||
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
|
||||
externalTensorData:(nullable NSMutableData*)externalTensorData
|
||||
error:(NSError**)error {
|
||||
- (nullable instancetype)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue
|
||||
externalTensorData:(nullable NSMutableData*)externalTensorData
|
||||
error:(NSError**)error {
|
||||
if ((self = [super init]) == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
try {
|
||||
_value = Ort::Value{CAPIOrtValue};
|
||||
_typeInfo = _value->GetTypeInfo();
|
||||
_typeInfo = existingCXXAPIOrtValue.GetTypeInfo();
|
||||
_externalTensorData = externalTensorData;
|
||||
|
||||
// transfer C++ Ort::Value ownership to this instance
|
||||
_value = std::move(existingCXXAPIOrtValue);
|
||||
return self;
|
||||
}
|
||||
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error);
|
||||
|
||||
@@ -9,9 +9,18 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ORTValue ()
|
||||
|
||||
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
|
||||
externalTensorData:(nullable NSMutableData*)externalTensorData
|
||||
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
|
||||
/**
|
||||
* Creates a value from an existing C++ API Ort::Value and takes ownership from it.
|
||||
* Note: Ownership is guaranteed to be transferred on success but not otherwise.
|
||||
*
|
||||
* @param existingCXXAPIOrtValue The existing C++ API Ort::Value.
|
||||
* @param externalTensorData Any external tensor data referenced by `existingCXXAPIOrtValue`.
|
||||
* @param error Optional error information set if an error occurs.
|
||||
* @return The instance, or nil if an error occurs.
|
||||
*/
|
||||
- (nullable instancetype)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue
|
||||
externalTensorData:(nullable NSMutableData*)externalTensorData
|
||||
error:(NSError**)error NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
- (Ort::Value&)CXXAPIOrtValue;
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
:©
|
||||
E
|
||||
imagebgr_dataDecodeImage"DecodeImage:com.microsoft.extensionsDecodeImageZ
|
||||
image
|
||||
|
||||
image_lengthb2
|
||||
bgr_data&
|
||||
$
|
||||
|
||||
bgr_data_h
|
||||
|
||||
bgr_data_w
|
||||
B
|
||||
com.microsoft.extensions
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
import XCTest
|
||||
import Foundation
|
||||
@testable import OnnxRuntimeBindings
|
||||
@testable import OnnxRuntimeExtensions
|
||||
|
||||
final class SwiftOnnxRuntimeExtensionsTests: XCTestCase {
|
||||
|
||||
let modelPath: String = Bundle.module.url(forResource: "decode_image", withExtension: "onnx")!.path
|
||||
|
||||
func testCreateSessionWithCustomOps() throws {
|
||||
let env = try ORTEnv(loggingLevel: ORTLoggingLevel.verbose)
|
||||
let options = try ORTSessionOptions()
|
||||
try options.setLogSeverityLevel(ORTLoggingLevel.verbose)
|
||||
try options.setIntraOpNumThreads(1)
|
||||
|
||||
// Register Custom Ops library using function pointer
|
||||
let ortCustomOpsFnPtr = OrtExt.getRegisterCustomOpsFunctionPointer()
|
||||
try options.registerCustomOps(functionPointer: ortCustomOpsFnPtr)
|
||||
|
||||
// Create the ORTSession
|
||||
_ = try ORTSession(env: env, modelPath: modelPath, sessionOptions: options)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user