From 038da1b01a0f7b2ffcfadbed97731360365e34f8 Mon Sep 17 00:00:00 2001 From: rachguo Date: Mon, 10 Jul 2023 23:43:08 -0700 Subject: [PATCH 01/70] add Package.swift --- Package.swift | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 Package.swift diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..e053732 --- /dev/null +++ b/Package.swift @@ -0,0 +1,109 @@ +// 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: [ +// .package(url: "https://github.com/microsoft/onnxruntime", branch: "rel-1.15.0"), +// ... +// ], +// +// NOTE: The direct consumption creates a somewhat complicated setup to 'release' a new version of the ORT SPM package. +// TBD: how to manage the release process + +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: ["test", "docs", "ReadMe.md", "format_objc.sh", + "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", + "-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 branch of ORT github repo: +// Target will be set to the released pod archive and its checksum. +// +// Any other branch/tag of ORT github repo: +// Invalid by default. We do not have a pod archive that is guaranteed to work +// as the objective-c bindings may have changed since the pod archive was released. + +// 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 { + // When creating the release version: + // - remove the fatalError + // - uncomment the package.targets.append call + // - update the major/minor/patch version info in the url + // - insert the checksum info from the onnxruntime-ios-packaging-pipeline CI's 'Print ORT iOS Pod checksum' + // stage output (or download the pod archive artifact from the CI and run `shasum -a 256 ` + // to manually calculate it). + // The checksum length and chars should look something like + // "c89cd106ff02eb3892243acd7c4f2bd8e68c2c94f2751b5e35f98722e10c042b" + // + // package.targets.append( + // Target.binaryTarget(name: "onnxruntime", + // url: "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-.zip", + // checksum: "Insert checksum here") + // ) + + fatalError("It is not valid to use a non-release branch from https://github.com/microsoft/onnxruntime.\n" + + "Please use a release branch (e.g. rel-1.15.0), or build the ONNX Runtime iOS pod archive locally " + + "and set the ORT_IOS_POD_LOCAL_PATH environment variable.\n" + + "See Package.swift for more information on using a local pod archive.") +} From bfd9340bfe95e3bbe24cc5442ad932417a4fb795 Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 00:06:58 -0700 Subject: [PATCH 02/70] pull swift/ and objc/ folder contents --- objectivec/.DS_Store | Bin 0 -> 6148 bytes objectivec/ReadMe.md | 2 + objectivec/assert_arc_enabled.mm | 4 + objectivec/cxx_api.h | 40 ++ objectivec/cxx_utils.h | 32 ++ objectivec/cxx_utils.mm | 94 +++++ objectivec/error_utils.h | 34 ++ objectivec/error_utils.mm | 37 ++ objectivec/format_objc.sh | 9 + objectivec/include/onnxruntime.h | 13 + objectivec/include/onnxruntime_training.h | 9 + objectivec/include/ort_checkpoint.h | 119 ++++++ .../include/ort_coreml_execution_provider.h | 62 +++ .../include/ort_custom_op_registration.h | 23 ++ objectivec/include/ort_enums.h | 55 +++ objectivec/include/ort_env.h | 44 ++ objectivec/include/ort_session.h | 300 ++++++++++++++ objectivec/include/ort_training_session.h | 263 ++++++++++++ objectivec/include/ort_value.h | 94 +++++ .../include/ort_xnnpack_execution_provider.h | 39 ++ objectivec/ort_checkpoint.mm | 111 +++++ objectivec/ort_checkpoint_internal.h | 16 + objectivec/ort_coreml_execution_provider.mm | 44 ++ objectivec/ort_enums.mm | 133 ++++++ objectivec/ort_enums_internal.h | 17 + objectivec/ort_env.mm | 43 ++ objectivec/ort_env_internal.h | 16 + objectivec/ort_session.mm | 387 ++++++++++++++++++ objectivec/ort_session_internal.h | 22 + objectivec/ort_training_session.mm | 224 ++++++++++ objectivec/ort_training_session_internal.h | 16 + objectivec/ort_value.mm | 162 ++++++++ objectivec/ort_value_internal.h | 29 ++ objectivec/ort_xnnpack_execution_provider.mm | 31 ++ objectivec/test/assert_arc_enabled.mm | 4 + objectivec/test/assertion_utils.h | 46 +++ objectivec/test/ort_checkpoint_test.mm | 117 ++++++ objectivec/test/ort_env_test.mm | 30 ++ objectivec/test/ort_session_test.mm | 264 ++++++++++++ objectivec/test/ort_training_session_test.mm | 359 ++++++++++++++++ objectivec/test/ort_training_utils_test.mm | 26 ++ objectivec/test/ort_value_test.mm | 79 ++++ objectivec/test/test_utils.h | 21 + objectivec/test/test_utils.mm | 44 ++ objectivec/test/testdata/gen_models.sh | 12 + objectivec/test/testdata/single_add.basic.ort | Bin 0 -> 1296 bytes objectivec/test/testdata/single_add.onnx | Bin 0 -> 93 bytes objectivec/test/testdata/single_add_gen.py | 19 + swift/.DS_Store | Bin 0 -> 6148 bytes swift/OnnxRuntimeBindingsTests/.DS_Store | Bin 0 -> 6148 bytes .../Resources/single_add.basic.ort | Bin 0 -> 1296 bytes .../SwiftOnnxRuntimeBindingsTests.swift | 62 +++ 52 files changed, 3607 insertions(+) create mode 100644 objectivec/.DS_Store create mode 100644 objectivec/ReadMe.md create mode 100644 objectivec/assert_arc_enabled.mm create mode 100644 objectivec/cxx_api.h create mode 100644 objectivec/cxx_utils.h create mode 100644 objectivec/cxx_utils.mm create mode 100644 objectivec/error_utils.h create mode 100644 objectivec/error_utils.mm create mode 100755 objectivec/format_objc.sh create mode 100644 objectivec/include/onnxruntime.h create mode 100644 objectivec/include/onnxruntime_training.h create mode 100644 objectivec/include/ort_checkpoint.h create mode 100644 objectivec/include/ort_coreml_execution_provider.h create mode 100644 objectivec/include/ort_custom_op_registration.h create mode 100644 objectivec/include/ort_enums.h create mode 100644 objectivec/include/ort_env.h create mode 100644 objectivec/include/ort_session.h create mode 100644 objectivec/include/ort_training_session.h create mode 100644 objectivec/include/ort_value.h create mode 100644 objectivec/include/ort_xnnpack_execution_provider.h create mode 100644 objectivec/ort_checkpoint.mm create mode 100644 objectivec/ort_checkpoint_internal.h create mode 100644 objectivec/ort_coreml_execution_provider.mm create mode 100644 objectivec/ort_enums.mm create mode 100644 objectivec/ort_enums_internal.h create mode 100644 objectivec/ort_env.mm create mode 100644 objectivec/ort_env_internal.h create mode 100644 objectivec/ort_session.mm create mode 100644 objectivec/ort_session_internal.h create mode 100644 objectivec/ort_training_session.mm create mode 100644 objectivec/ort_training_session_internal.h create mode 100644 objectivec/ort_value.mm create mode 100644 objectivec/ort_value_internal.h create mode 100644 objectivec/ort_xnnpack_execution_provider.mm create mode 100644 objectivec/test/assert_arc_enabled.mm create mode 100644 objectivec/test/assertion_utils.h create mode 100644 objectivec/test/ort_checkpoint_test.mm create mode 100644 objectivec/test/ort_env_test.mm create mode 100644 objectivec/test/ort_session_test.mm create mode 100644 objectivec/test/ort_training_session_test.mm create mode 100644 objectivec/test/ort_training_utils_test.mm create mode 100644 objectivec/test/ort_value_test.mm create mode 100644 objectivec/test/test_utils.h create mode 100644 objectivec/test/test_utils.mm create mode 100755 objectivec/test/testdata/gen_models.sh create mode 100644 objectivec/test/testdata/single_add.basic.ort create mode 100644 objectivec/test/testdata/single_add.onnx create mode 100644 objectivec/test/testdata/single_add_gen.py create mode 100644 swift/.DS_Store create mode 100644 swift/OnnxRuntimeBindingsTests/.DS_Store create mode 100644 swift/OnnxRuntimeBindingsTests/Resources/single_add.basic.ort create mode 100644 swift/OnnxRuntimeBindingsTests/SwiftOnnxRuntimeBindingsTests.swift diff --git a/objectivec/.DS_Store b/objectivec/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..67f406eedd1fc62e6d3c050cee15d2acd30bd6a1 GIT binary patch literal 6148 zcmeHKyJ`bL3>+nf7}B^*xxbJ!TnYFu6&wD4?@g2RY+q-AkD5$ zbIVR~IsvftX?O-!0G4z|e0rFhKX;$mU1f|&=Q~aq@HTwx$JgVm`g+2-4>;f*dyGH% z$MHHrSt%d|q<|EV0#e{l3V83OEgusVrGONW0^bVw_o2}pd*PHApALo?0f-Bx!?=!F zg4jGk?1fVzGc-#oF{xG~h9#Z(R&~8_N=!Peh7YTgttJ$U)A{}u<*=TpCaDZOd9Q8s7rNJc(cQQX3PZGGVzgs!yd6J9 cQPwqI^La0v5`)fs(24pPa9w0l;J+0(1EVPwfB*mh literal 0 HcmV?d00001 diff --git a/objectivec/ReadMe.md b/objectivec/ReadMe.md new file mode 100644 index 0000000..9b89726 --- /dev/null +++ b/objectivec/ReadMe.md @@ -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 diff --git a/objectivec/assert_arc_enabled.mm b/objectivec/assert_arc_enabled.mm new file mode 100644 index 0000000..9aa0bad --- /dev/null +++ b/objectivec/assert_arc_enabled.mm @@ -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."); diff --git a/objectivec/cxx_api.h b/objectivec/cxx_api.h new file mode 100644 index 0000000..b57c865 --- /dev/null +++ b/objectivec/cxx_api.h @@ -0,0 +1,40 @@ +// 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 +// clang-format off +#define STRINGIFY(x) #x +#ifdef SPM_BUILD +#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(onnxruntime/x) +#else +#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 + +#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h)) +#define ORT_OBJC_API_COREML_EP_AVAILABLE 1 +#include ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h) +#else +#define ORT_OBJC_API_COREML_EP_AVAILABLE 0 +#endif + +#if defined(__clang__) +#pragma clang diagnostic pop +#endif // defined(__clang__) diff --git a/objectivec/cxx_utils.h b/objectivec/cxx_utils.h new file mode 100644 index 0000000..0b3666d --- /dev/null +++ b/objectivec/cxx_utils.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#include +#include +#include + +#import "cxx_api.h" + +NS_ASSUME_NONNULL_BEGIN +@class ORTValue; + +namespace utils { + +NSString* toNSString(const std::string& str); +NSString* _Nullable toNullableNSString(const std::optional& str); + +std::string toStdString(NSString* str); +std::optional toStdOptionalString(NSString* _Nullable str); + +std::vector toStdStringVector(NSArray* strs); +NSArray* toNSStringNSArray(const std::vector& strs); + +NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& values, NSError** error); + +std::vector getWrappedCAPIOrtValues(NSArray* values); + +} // namespace utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/cxx_utils.mm b/objectivec/cxx_utils.mm new file mode 100644 index 0000000..01d0955 --- /dev/null +++ b/objectivec/cxx_utils.mm @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "cxx_utils.h" + +#include +#include +#include + +#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& str) { + if (str.has_value()) { + return toNSString(*str); + } + return nil; +} + +std::string toStdString(NSString* str) { + return std::string([str UTF8String]); +} + +std::optional toStdOptionalString(NSString* _Nullable str) { + if (str) { + return std::optional([str UTF8String]); + } + return std::nullopt; +} + +std::vector toStdStringVector(NSArray* strs) { + std::vector result; + result.reserve(strs.count); + for (NSString* str in strs) { + result.push_back([str UTF8String]); + } + return result; +} + +NSArray* toNSStringNSArray(const std::vector& strs) { + NSMutableArray* result = [NSMutableArray arrayWithCapacity:strs.size()]; + for (const std::string& str : strs) { + [result addObject:toNSString(str)]; + } + return result; +} + +NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& CAPIValues, NSError** error) { + NSMutableArray* 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 getWrappedCAPIOrtValues(NSArray* values) { + std::vector result; + result.reserve(values.count); + for (ORTValue* val in values) { + result.push_back(static_cast([val CXXAPIOrtValue])); + } + return result; +} + +} // namespace utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/error_utils.h b/objectivec/error_utils.h new file mode 100644 index 0000000..4df71ce --- /dev/null +++ b/objectivec/error_utils.h @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#include + +#import "cxx_api.h" + +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); + +// 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 diff --git a/objectivec/error_utils.mm b/objectivec/error_utils.mm new file mode 100644 index 0000000..335cf88 --- /dev/null +++ b/objectivec/error_utils.mm @@ -0,0 +1,37 @@ +// 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 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); +} + +void ORTSaveExceptionToError(const std::exception& e, NSError** error) { + ORTSaveCodeAndDescriptionToError(ORT_RUNTIME_EXCEPTION, e.what(), error); +} + +NS_ASSUME_NONNULL_END diff --git a/objectivec/format_objc.sh b/objectivec/format_objc.sh new file mode 100755 index 0000000..75ab071 --- /dev/null +++ b/objectivec/format_objc.sh @@ -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") diff --git a/objectivec/include/onnxruntime.h b/objectivec/include/onnxruntime.h new file mode 100644 index 0000000..c7bfe6f --- /dev/null +++ b/objectivec/include/onnxruntime.h @@ -0,0 +1,13 @@ +// 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_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" diff --git a/objectivec/include/onnxruntime_training.h b/objectivec/include/onnxruntime_training.h new file mode 100644 index 0000000..504447e --- /dev/null +++ b/objectivec/include/onnxruntime_training.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" diff --git a/objectivec/include/ort_checkpoint.h b/objectivec/include/ort_checkpoint.h new file mode 100644 index 0000000..85e5844 --- /dev/null +++ b/objectivec/include/ort_checkpoint.h @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#include + +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 diff --git a/objectivec/include/ort_coreml_execution_provider.h b/objectivec/include/ort_coreml_execution_provider.h new file mode 100644 index 0000000..a015b6f --- /dev/null +++ b/objectivec/include/ort_coreml_execution_provider.h @@ -0,0 +1,62 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#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 diff --git a/objectivec/include/ort_custom_op_registration.h b/objectivec/include/ort_custom_op_registration.h new file mode 100644 index 0000000..8d50b92 --- /dev/null +++ b/objectivec/include/ort_custom_op_registration.h @@ -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*/); diff --git a/objectivec/include/ort_enums.h b/objectivec/include/ort_enums.h new file mode 100644 index 0000000..d505ce2 --- /dev/null +++ b/objectivec/include/ort_enums.h @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +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 diff --git a/objectivec/include/ort_env.h b/objectivec/include/ort_env.h new file mode 100644 index 0000000..8456b57 --- /dev/null +++ b/objectivec/include/ort_env.h @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#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* _Nullable 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 diff --git a/objectivec/include/ort_session.h b/objectivec/include/ort_session.h new file mode 100644 index 0000000..cfdb3bf --- /dev/null +++ b/objectivec/include/ort_session.h @@ -0,0 +1,300 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_custom_op_registration.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*)inputs + outputs:(NSDictionary*)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*)runWithInputs:(NSDictionary*)inputs + outputNames:(NSSet*)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*)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*)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*)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*)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);` + * + * 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. + */ +- (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; + +@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 diff --git a/objectivec/include/ort_training_session.h b/objectivec/include/ort_training_session.h new file mode 100644 index 0000000..15c0137 --- /dev/null +++ b/objectivec/include/ort_training_session.h @@ -0,0 +1,263 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#include + +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*)trainStepWithInputValues:(NSArray*)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*)evalStepWithInputValues:(NSArray*)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*)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*)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*)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*)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*)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 diff --git a/objectivec/include/ort_value.h b/objectivec/include/ort_value.h new file mode 100644 index 0000000..60a9bbe --- /dev/null +++ b/objectivec/include/ort_value.h @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#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*)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* shape; + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/include/ort_xnnpack_execution_provider.h b/objectivec/include/ort_xnnpack_execution_provider.h new file mode 100644 index 0000000..489fd43 --- /dev/null +++ b/objectivec/include/ort_xnnpack_execution_provider.h @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#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 diff --git a/objectivec/ort_checkpoint.mm b/objectivec/ort_checkpoint.mm new file mode 100644 index 0000000..1238645 --- /dev/null +++ b/objectivec/ort_checkpoint.mm @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_checkpoint_internal.h" + +#include +#include +#include +#import "cxx_api.h" + +#import "error_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@implementation ORTCheckpoint { + std::optional _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(&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(&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(&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 diff --git a/objectivec/ort_checkpoint_internal.h b/objectivec/ort_checkpoint_internal.h new file mode 100644 index 0000000..3d1550c --- /dev/null +++ b/objectivec/ort_checkpoint_internal.h @@ -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 diff --git a/objectivec/ort_coreml_execution_provider.mm b/objectivec/ort_coreml_execution_provider.mm new file mode 100644 index 0000000..6340fde --- /dev/null +++ b/objectivec/ort_coreml_execution_provider.mm @@ -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(options); + ORTSaveCodeAndDescriptionToError(ORT_FAIL, "CoreML execution provider is not enabled.", error); + return NO; +#endif +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_enums.mm b/objectivec/ort_enums.mm new file mode 100644 index 0000000..0144a33 --- /dev/null +++ b/objectivec/ort_enums.mm @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_enums_internal.h" + +#include + +#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 +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"); +} diff --git a/objectivec/ort_enums_internal.h b/objectivec/ort_enums_internal.h new file mode 100644 index 0000000..f1470d7 --- /dev/null +++ b/objectivec/ort_enums_internal.h @@ -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); diff --git a/objectivec/ort_env.mm b/objectivec/ort_env.mm new file mode 100644 index 0000000..7043785 --- /dev/null +++ b/objectivec/ort_env.mm @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_env_internal.h" + +#include + +#import "cxx_api.h" + +#import "error_utils.h" +#import "ort_enums_internal.h" + +NS_ASSUME_NONNULL_BEGIN + +NSString* _Nullable ORTVersion(void) { + return [NSString stringWithUTF8String:OrtGetApiBase()->GetVersionString()]; +} + +@implementation ORTEnv { + std::optional _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 diff --git a/objectivec/ort_env_internal.h b/objectivec/ort_env_internal.h new file mode 100644 index 0000000..32df9bb --- /dev/null +++ b/objectivec/ort_env_internal.h @@ -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 diff --git a/objectivec/ort_session.mm b/objectivec/ort_session.mm new file mode 100644 index 0000000..0255e7b --- /dev/null +++ b/objectivec/ort_session.mm @@ -0,0 +1,387 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_session_internal.h" + +#include +#include + +#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 _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*)inputs + outputs:(NSDictionary*)outputs + runOptions:(nullable ORTRunOptions*)runOptions + error:(NSError**)error { + try { + if (!runOptions) { + runOptions = [[ORTRunOptions alloc] initWithError:error]; + if (!runOptions) { + return NO; + } + } + + std::vector inputNames, outputNames; + std::vector inputCAPIValues; + std::vector outputCAPIValues; + + inputNames.reserve(inputs.count); + inputCAPIValues.reserve(inputs.count); + for (NSString* inputName in inputs) { + inputNames.push_back(inputName.UTF8String); + inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + } + + outputNames.reserve(outputs.count); + outputCAPIValues.reserve(outputs.count); + for (NSString* outputName in outputs) { + outputNames.push_back(outputName.UTF8String); + outputCAPIValues.push_back(static_cast([outputs[outputName] CXXAPIOrtValue])); + } + + Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], + inputNames.data(), inputCAPIValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputCAPIValues.data())); + + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +- (nullable NSDictionary*)runWithInputs:(NSDictionary*)inputs + outputNames:(NSSet*)outputNameSet + runOptions:(nullable ORTRunOptions*)runOptions + error:(NSError**)error { + try { + if (!runOptions) { + runOptions = [[ORTRunOptions alloc] initWithError:error]; + if (!runOptions) { + return nil; + } + } + + NSArray* outputNameArray = outputNameSet.allObjects; + + std::vector inputNames, outputNames; + std::vector inputCAPIValues; + std::vector outputCAPIValues; + + inputNames.reserve(inputs.count); + inputCAPIValues.reserve(inputs.count); + for (NSString* inputName in inputs) { + inputNames.push_back(inputName.UTF8String); + inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + } + + outputNames.reserve(outputNameArray.count); + outputCAPIValues.reserve(outputNameArray.count); + for (NSString* outputName in outputNameArray) { + outputNames.push_back(outputName.UTF8String); + outputCAPIValues.push_back(nullptr); + } + + Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], + inputNames.data(), inputCAPIValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputCAPIValues.data())); + + NSMutableDictionary* outputs = [[NSMutableDictionary alloc] init]; + for (NSUInteger i = 0; i < outputNameArray.count; ++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 outputCXXAPIValue{outputCAPIValues[i]}; + ORTValue* outputValue = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(outputCXXAPIValue) + externalTensorData:nil + error:error]; + if (!outputValue) { + // 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; + } + + outputs[outputNameArray[i]] = outputValue; + } + + return outputs; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)inputNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::Input error:error]; +} + +- (nullable NSArray*)overridableInitializerNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::OverridableInitializer error:error]; +} + +- (nullable NSArray*)outputNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::Output error:error]; +} + +#pragma mark - Private + +- (nullable NSArray*)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* 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 _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*)providerOptions + error:(NSError**)error { + try { + std::unordered_map 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) +} + +- (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(*_sessionOptions), + OrtGetApiBase())); + return YES; + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) +} + +#pragma mark - Internal + +- (Ort::SessionOptions&)CXXAPIOrtSessionOptions { + return *_sessionOptions; +} + +@end + +@implementation ORTRunOptions { + std::optional _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 diff --git a/objectivec/ort_session_internal.h b/objectivec/ort_session_internal.h new file mode 100644 index 0000000..c250264 --- /dev/null +++ b/objectivec/ort_session_internal.h @@ -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 diff --git a/objectivec/ort_training_session.mm b/objectivec/ort_training_session.mm new file mode 100644 index 0000000..285151b --- /dev/null +++ b/objectivec/ort_training_session.mm @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_training_session_internal.h" + +#import +#import +#import + +#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 _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 evalPath = utils::toStdOptionalString(evalModelPath); + std::optional 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*)trainStepWithInputValues:(NSArray*)inputs + error:(NSError**)error { + try { + std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); + + size_t outputCount; + Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetTrainingModelOutputCount(*_session, &outputCount)); + std::vector 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*)evalStepWithInputValues:(NSArray*)inputs + error:(NSError**)error { + try { + // create vector of OrtValue from NSArray with same size as inputValues + std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); + + size_t outputCount; + Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetEvalModelOutputCount(*_session, &outputCount)); + std::vector 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*)getTrainInputNamesWithError:(NSError**)error { + try { + std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(true); + return utils::toNSStringNSArray(inputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getTrainOutputNamesWithError:(NSError**)error { + try { + std::vector outputNames = [self CXXAPIOrtTrainingSession].OutputNames(true); + return utils::toNSStringNSArray(outputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getEvalInputNamesWithError:(NSError**)error { + try { + std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(false); + return utils::toNSStringNSArray(inputNames); + } + ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) +} + +- (nullable NSArray*)getEvalOutputNamesWithError:(NSError**)error { + try { + std::vector 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*)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 diff --git a/objectivec/ort_training_session_internal.h b/objectivec/ort_training_session_internal.h new file mode 100644 index 0000000..453c941 --- /dev/null +++ b/objectivec/ort_training_session_internal.h @@ -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 diff --git a/objectivec/ort_value.mm b/objectivec/ort_value.mm new file mode 100644 index 0000000..f6ea674 --- /dev/null +++ b/objectivec/ort_value.mm @@ -0,0 +1,162 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_value_internal.h" + +#include + +#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 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 _value; + std::optional _typeInfo; +} + +#pragma mark - Public + +- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData + elementType:(ORTTensorElementDataType)elementType + shape:(NSArray*)shape + error:(NSError**)error { + try { + const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + const auto ONNXElementType = PublicToCAPITensorElementType(elementType); + const auto shapeVector = [shape]() { + std::vector 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 initWithCXXAPIOrtValue:std::move(ortValue) + 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)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue + externalTensorData:(nullable NSMutableData*)externalTensorData + error:(NSError**)error { + if ((self = [super init]) == nil) { + return nil; + } + + try { + _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); +} + +- (Ort::Value&)CXXAPIOrtValue { + return *_value; +} + +@end + +@implementation ORTValueTypeInfo +@end + +@implementation ORTTensorTypeAndShapeInfo +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_value_internal.h b/objectivec/ort_value_internal.h new file mode 100644 index 0000000..6bc2e9b --- /dev/null +++ b/objectivec/ort_value_internal.h @@ -0,0 +1,29 @@ +// 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 () + +/** + * 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; + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_xnnpack_execution_provider.mm b/objectivec/ort_xnnpack_execution_provider.mm new file mode 100644 index 0000000..324974a --- /dev/null +++ b/objectivec/ort_xnnpack_execution_provider.mm @@ -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 diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm new file mode 100644 index 0000000..9aa0bad --- /dev/null +++ b/objectivec/test/assert_arc_enabled.mm @@ -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."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h new file mode 100644 index 0000000..2b72435 --- /dev/null +++ b/objectivec/test/assertion_utils.h @@ -0,0 +1,46 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#define ORTAssertNullableResultSuccessful(result, error) \ + do { \ + XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertBoolResultSuccessful(result, error) \ + do { \ + XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertNullableResultUnsuccessful(result, error) \ + do { \ + XCTAssertNil(result); \ + XCTAssertNotNil(error); \ + } while (0) + +#define ORTAssertBoolResultUnsuccessful(result, error) \ + do { \ + XCTAssertFalse(result); \ + XCTAssertNotNil(error); \ + } while (0) + +#define ORTAssertEqualFloatAndNoError(expected, result, error) \ + do { \ + XCTAssertEqualWithAccuracy(expected, result, 1e-3f, @"Expected %f but got %f. Error:%@", expected, result, error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertEqualFloatArrays(expected, result) \ + do { \ + XCTAssertEqual(expected.count, result.count); \ + for (size_t i = 0; i < expected.count; ++i) { \ + XCTAssertEqualWithAccuracy([expected[i] floatValue], [result[i] floatValue], 1e-3f); \ + } \ + } while (0) + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_checkpoint_test.mm b/objectivec/test/ort_checkpoint_test.mm new file mode 100644 index 0000000..9b2196f --- /dev/null +++ b/objectivec/test/ort_checkpoint_test.mm @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_checkpoint.h" +#import "ort_training_session.h" +#import "ort_env.h" +#import "ort_session.h" + +#import "test/test_utils.h" +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTCheckpointTest : XCTestCase +@property(readonly, nullable) ORTEnv* ortEnv; +@end + +@implementation ORTCheckpointTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); +} + ++ (NSString*)getCheckpointPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"checkpoint.ckpt"]; + return path; +} + ++ (NSString*)getTrainingModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"training_model.onnx"]; + return path; +} + +- (void)testSaveCheckpoint { + NSError* error = nil; + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // save checkpoint + NSString* path = [test_utils::createTemporaryDirectory(self) stringByAppendingPathComponent:@"save_checkpoint.ckpt"]; + XCTAssertNotNil(path); + BOOL result = [checkpoint saveCheckpointToPath:path withOptimizerState:NO error:&error]; + + ORTAssertBoolResultSuccessful(result, error); +} + +- (void)testInitCheckpoint { + NSError* error = nil; + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); +} + +- (void)testIntProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addIntPropertyWithName:@"test" value:314 error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + int64_t value = [checkpoint getIntPropertyWithName:@"test" error:&error]; + XCTAssertEqual(value, 314); +} + +- (void)testFloatProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addFloatPropertyWithName:@"test" value:3.14f error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + float value = [checkpoint getFloatPropertyWithName:@"test" error:&error]; + XCTAssertEqual(value, 3.14f); +} + +- (void)testStringProperty { + NSError* error = nil; + // Load checkpoint + ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; + ORTAssertNullableResultSuccessful(checkpoint, error); + + // Add property + BOOL result = [checkpoint addStringPropertyWithName:@"test" value:@"hello" error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + // Get property + NSString* value = [checkpoint getStringPropertyWithName:@"test" error:&error]; + XCTAssertEqualObjects(value, @"hello"); +} + +- (void)tearDown { + _ortEnv = nil; + + [super tearDown]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm new file mode 100644 index 0000000..420f55f --- /dev/null +++ b/objectivec/test/ort_env_test.mm @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_env.h" + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTEnvTest : XCTestCase +@end + +@implementation ORTEnvTest +- (void)testGetOrtVersion { + NSString* ver = ORTVersion(); + XCTAssertNotNil(ver); +} + +- (void)testInitOk { + NSError* err = nil; + ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(env, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm new file mode 100644 index 0000000..57b92fd --- /dev/null +++ b/objectivec/test/ort_session_test.mm @@ -0,0 +1,264 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_coreml_execution_provider.h" +#import "ort_xnnpack_execution_provider.h" +#import "ort_env.h" +#import "ort_session.h" +#import "ort_value.h" + +#import "test/assertion_utils.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTSessionTest : XCTestCase + +@property(readonly, nullable) ORTEnv* ortEnv; + +@end + +@implementation ORTSessionTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); +} + +- (void)tearDown { + _ortEnv = nil; + + [super tearDown]; +} + +// model with an Add op +// inputs: A, B +// output: C = A + B ++ (NSString*)getAddModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; + NSString* path = [bundle pathForResource:@"single_add.basic" + ofType:@"ort"]; + return path; +} + ++ (NSMutableData*)dataWithScalarFloat:(float)value { + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; + return data; +} + ++ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { + NSArray* shape = @[ @1 ]; + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeFloat + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + return ortValue; +} + ++ (ORTSessionOptions*)makeSessionOptions { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(sessionOptions, err); + return sessionOptions; +} + ++ (ORTRunOptions*)makeRunOptions { + NSError* err = nil; + ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(runOptions, err); + return runOptions; +} + +- (void)testInitAndRunWithPreallocatedOutputOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultSuccessful(runResult, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testInitAndRunOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSDictionary* outputs = + [session runWithInputs:@{@"A" : a, @"B" : b} + outputNames:[NSSet setWithArray:@[ @"C" ]] + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertNullableResultSuccessful(outputs, err); + + ORTValue* cOutput = outputs[@"C"]; + XCTAssertNotNil(cOutput); + + NSData* cData = [cOutput tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(cData, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testGetNamesOk { + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSArray* inputNames = [session inputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(inputNames, err); + XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); + + NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; + ORTAssertNullableResultSuccessful(overridableInitializerNames, err); + XCTAssertEqualObjects(overridableInitializerNames, (@[])); + + NSArray* outputNames = [session outputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(outputNames, err); + XCTAssertEqualObjects(outputNames, (@[ @"C" ])); +} + +- (void)testInitFailsWithInvalidPath { + NSString* invalidModelPath = @"invalid/path/to/model.ort"; + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:invalidModelPath + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultUnsuccessful(session, err); +} + +- (void)testRunFailsWithInvalidInput { + NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"D" : d} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultUnsuccessful(runResult, err); +} + +- (void)testAppendCoreMLEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; + coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option + + BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions + error:&err]; + + if (!ORTIsCoreMLExecutionProviderAvailable()) { + ORTAssertBoolResultUnsuccessful(appendResult, err); + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} + +- (void)testAppendXnnpackEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; + XnnpackOptions.intra_op_num_threads = 2; + + BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions + error:&err]; + // Without xnnpack EP in building also can pass the test + NSString* err_msg = [err localizedDescription]; + if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} + +static bool gDummyRegisterCustomOpsFnCalled = false; + +static OrtStatus* _Nullable DummyRegisterCustomOpsFn(OrtSessionOptions* /*session_options*/, + const OrtApiBase* /*api*/) { + gDummyRegisterCustomOpsFnCalled = true; + return nullptr; +} + +- (void)testRegisterCustomOpsUsingFunctionPointer { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + + gDummyRegisterCustomOpsFnCalled = false; + BOOL registerResult = [sessionOptions registerCustomOpsUsingFunctionPointer:&DummyRegisterCustomOpsFn + error:&err]; + ORTAssertBoolResultSuccessful(registerResult, err); + + XCTAssertEqual(gDummyRegisterCustomOpsFnCalled, true); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_session_test.mm b/objectivec/test/ort_training_session_test.mm new file mode 100644 index 0000000..683965d --- /dev/null +++ b/objectivec/test/ort_training_session_test.mm @@ -0,0 +1,359 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_checkpoint.h" +#import "ort_training_session.h" +#import "ort_env.h" +#import "ort_session.h" +#import "ort_value.h" + +#import "test/test_utils.h" +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTTrainingSessionTest : XCTestCase +@property(readonly, nullable) ORTEnv* ortEnv; +@property(readonly, nullable) ORTCheckpoint* checkpoint; +@property(readonly, nullable) ORTTrainingSession* session; +@end + +@implementation ORTTrainingSessionTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); + _checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTTrainingSessionTest + getFilePathFromName:@"checkpoint.ckpt"] + error:&err]; + ORTAssertNullableResultSuccessful(_checkpoint, err); + _session = [self makeTrainingSessionWithCheckpoint:_checkpoint]; +} + ++ (NSString*)getFilePathFromName:(NSString*)name { + NSBundle* bundle = [NSBundle bundleForClass:[ORTTrainingSessionTest class]]; + NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:name]; + return path; +} + ++ (NSMutableData*)loadTensorDataFromFile:(NSString*)filePath skipHeader:(BOOL)skipHeader { + NSError* error = nil; + NSString* fileContents = [NSString stringWithContentsOfFile:filePath + encoding:NSUTF8StringEncoding + error:&error]; + ORTAssertNullableResultSuccessful(fileContents, error); + + NSArray* lines = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + + if (skipHeader) { + lines = [lines subarrayWithRange:NSMakeRange(1, lines.count - 1)]; + } + + NSArray* dataArray = [lines[0] componentsSeparatedByCharactersInSet: + [NSCharacterSet characterSetWithCharactersInString:@",[] "]]; + NSMutableData* tensorData = [NSMutableData data]; + + for (NSString* str in dataArray) { + if (str.length > 0) { + float value = [str floatValue]; + [tensorData appendBytes:&value length:sizeof(float)]; + } + } + + return tensorData; +} + +- (ORTTrainingSession*)makeTrainingSessionWithCheckpoint:(ORTCheckpoint*)checkpoint { + NSError* error = nil; + ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&error]; + ORTAssertNullableResultSuccessful(sessionOptions, error); + + ORTTrainingSession* session = [[ORTTrainingSession alloc] + initWithEnv:self.ortEnv + sessionOptions:sessionOptions + checkpoint:checkpoint + trainModelPath:[ORTTrainingSessionTest getFilePathFromName:@"training_model.onnx"] + evalModelPath:[ORTTrainingSessionTest getFilePathFromName:@"eval_model.onnx"] + optimizerModelPath:[ORTTrainingSessionTest getFilePathFromName:@"adamw.onnx"] + error:&error]; + + ORTAssertNullableResultSuccessful(session, error); + return session; +} + +- (void)testInitTrainingSession { + NSError* error = nil; + + // check that inputNames contains input-0 + NSArray* inputNames = [self.session getTrainInputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(inputNames, error); + + XCTAssertTrue(inputNames.count > 0); + XCTAssertTrue([inputNames containsObject:@"input-0"]); + + // check that outNames contains onnx::loss::21273 + NSArray* outputNames = [self.session getTrainOutputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(outputNames, error); + + XCTAssertTrue(outputNames.count > 0); + XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); +} + +- (void)testInitTrainingSessionWithEval { + NSError* error = nil; + + // check that inputNames contains input-0 + NSArray* inputNames = [self.session getEvalInputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(inputNames, error); + + XCTAssertTrue(inputNames.count > 0); + XCTAssertTrue([inputNames containsObject:@"input-0"]); + + // check that outNames contains onnx::loss::21273 + NSArray* outputNames = [self.session getEvalOutputNamesWithError:&error]; + ORTAssertNullableResultSuccessful(outputNames, error); + + XCTAssertTrue(outputNames.count > 0); + XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); +} + +- (void)runTrainStep { + // load input and expected output + NSError* error = nil; + NSMutableData* expectedOutput = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_1.out"] + skipHeader:YES]; + + NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"input-0.in"] + skipHeader:YES]; + + int32_t labels[] = {1, 1}; + + // create ORTValue array for input and labels + NSMutableArray* inputValues = [NSMutableArray array]; + + ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input + elementType:ORTTensorElementDataTypeFloat + shape:@[ @2, @784 ] + error:&error]; + ORTAssertNullableResultSuccessful(inputTensor, error); + [inputValues addObject:inputTensor]; + + ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels + length:sizeof(labels)] + elementType:ORTTensorElementDataTypeInt32 + shape:@[ @2 ] + error:&error]; + + ORTAssertNullableResultSuccessful(labelTensor, error); + [inputValues addObject:labelTensor]; + + NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + XCTAssertTrue(outputs.count > 0); + + BOOL result = [self.session lazyResetGradWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + XCTAssertTrue(outputs.count > 0); + + ORTValue* outputValue = outputs[0]; + ORTValueTypeInfo* typeInfo = [outputValue typeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(typeInfo, error); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); + + ORTTensorTypeAndShapeInfo* tensorInfo = [outputValue tensorTypeAndShapeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(tensorInfo, error); + XCTAssertEqual(tensorInfo.elementType, ORTTensorElementDataTypeFloat); + + NSMutableData* tensorData = [outputValue tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(tensorData, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(tensorData), + test_utils::getFloatArrayFromData(expectedOutput)); +} + +- (void)testTrainStepOutput { + [self runTrainStep]; +} + +- (void)testOptimizerStep { + // load input and expected output + NSError* error = nil; + NSMutableData* expectedOutput1 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_1.out"] + skipHeader:YES]; + + NSMutableData* expectedOutput2 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"loss_2.out"] + skipHeader:YES]; + + NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest + getFilePathFromName:@"input-0.in"] + skipHeader:YES]; + + int32_t labels[] = {1, 1}; + + // create ORTValue array for input and labels + NSMutableArray* inputValues = [NSMutableArray array]; + + ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input + elementType:ORTTensorElementDataTypeFloat + shape:@[ @2, @784 ] + error:&error]; + ORTAssertNullableResultSuccessful(inputTensor, error); + [inputValues addObject:inputTensor]; + + ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels + length:sizeof(labels)] + elementType:ORTTensorElementDataTypeInt32 + shape:@[ @2 ] + error:&error]; + ORTAssertNullableResultSuccessful(labelTensor, error); + [inputValues addObject:labelTensor]; + + // run train step, optimizer steps and check loss + NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + + NSMutableData* loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput1)); + + BOOL result = [self.session lazyResetGradWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + + loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput1)); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + + outputs = [self.session trainStepWithInputValues:inputValues error:&error]; + ORTAssertNullableResultSuccessful(outputs, error); + loss = [outputs[0] tensorDataWithError:&error]; + ORTAssertNullableResultSuccessful(loss, error); + ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), + test_utils::getFloatArrayFromData(expectedOutput2)); +} + +- (void)testSetLearningRate { + NSError* error = nil; + + float learningRate = 0.1f; + BOOL result = [self.session setLearningRate:learningRate error:&error]; + ORTAssertBoolResultSuccessful(result, error); + + float actualLearningRate = [self.session getLearningRateWithError:&error]; + ORTAssertEqualFloatAndNoError(learningRate, actualLearningRate, error); +} + +- (void)testLinearLRScheduler { + NSError* error = nil; + + float learningRate = 0.1f; + BOOL result = [self.session registerLinearLRSchedulerWithWarmupStepCount:2 + totalStepCount:4 + initialLr:learningRate + error:&error]; + + ORTAssertBoolResultSuccessful(result, error); + + [self runTrainStep]; + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.1f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); + + result = [self.session optimizerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + result = [self.session schedulerStepWithError:&error]; + ORTAssertBoolResultSuccessful(result, error); + ORTAssertEqualFloatAndNoError(0.0f, [self.session getLearningRateWithError:&error], error); +} + +- (void)testExportModelForInference { + NSError* error = nil; + + NSString* inferenceModelPath = [test_utils::createTemporaryDirectory(self) + stringByAppendingPathComponent:@"inference_model.onnx"]; + XCTAssertNotNil(inferenceModelPath); + + NSArray* graphOutputNames = [NSArray arrayWithObjects:@"output-0", nil]; + + BOOL result = [self.session exportModelForInferenceWithOutputPath:inferenceModelPath + graphOutputNames:graphOutputNames + error:&error]; + + ORTAssertBoolResultSuccessful(result, error); + XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:inferenceModelPath]); + + [self addTeardownBlock:^{ + NSError* error = nil; + [[NSFileManager defaultManager] removeItemAtPath:inferenceModelPath error:&error]; + }]; +} + +- (void)testToBuffer { + NSError* error = nil; + ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; + ORTAssertNullableResultSuccessful(buffer, error); + + ORTValueTypeInfo* typeInfo = [buffer typeInfoWithError:&error]; + ORTAssertNullableResultSuccessful(typeInfo, error); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); +} + +- (void)testFromBuffer { + NSError* error = nil; + + ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; + ORTAssertNullableResultSuccessful(buffer, error); + + BOOL result = [self.session fromBufferWithValue:buffer error:&error]; + ORTAssertBoolResultSuccessful(result, error); +} + +- (void)tearDown { + _session = nil; + _checkpoint = nil; + _ortEnv = nil; + + [super tearDown]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_utils_test.mm b/objectivec/test/ort_training_utils_test.mm new file mode 100644 index 0000000..1695ddc --- /dev/null +++ b/objectivec/test/ort_training_utils_test.mm @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#import "ort_training_session.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTTrainingUtilsTest : XCTestCase +@end + +@implementation ORTTrainingUtilsTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; +} + +- (void)testSetSeed { + ORTSetSeed(2718); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm new file mode 100644 index 0000000..734ad39 --- /dev/null +++ b/objectivec/test/ort_value_test.mm @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_value.h" + +#include + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTValueTest : XCTestCase +@end + +@implementation ORTValueTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; +} + +- (void)testInitTensorOk { + int32_t value = 42; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value + length:sizeof(int32_t)]; + NSArray* shape = @[ @1 ]; + + const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:elementType + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + + auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { + XCTAssertEqual(tensorInfo.elementType, elementType); + XCTAssertEqualObjects(tensorInfo.shape, shape); + }; + + ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(typeInfo, err); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); + checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); + + ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(tensorInfo, err); + checkTensorInfo(tensorInfo); + + NSData* actualData = [ortValue tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(actualData, err); + XCTAssertEqual(actualData.length, sizeof(int32_t)); + int32_t actualValue; + memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); + XCTAssertEqual(actualValue, value); +} + +- (void)testInitTensorFailsWithDataSmallerThanShape { + std::vector values{1, 2, 3, 4}; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() + length:values.size() * sizeof(int32_t)]; + NSArray* shape = @[ @2, @3 ]; // too large + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeInt32 + shape:shape + error:&err]; + ORTAssertNullableResultUnsuccessful(ortValue, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.h b/objectivec/test/test_utils.h new file mode 100644 index 0000000..8a5e6e4 --- /dev/null +++ b/objectivec/test/test_utils.h @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import +#import + +#import "ort_session.h" +#import "ort_env.h" +#import "ort_value.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace test_utils { + +NSString* _Nullable createTemporaryDirectory(XCTestCase* testCase); + +NSArray* getFloatArrayFromData(NSData* data); + +} // namespace test_utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.mm b/objectivec/test/test_utils.mm new file mode 100644 index 0000000..ef8e8c5 --- /dev/null +++ b/objectivec/test/test_utils.mm @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "test_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +namespace test_utils { + +NSString* createTemporaryDirectory(XCTestCase* testCase) { + NSString* temporaryDirectory = NSTemporaryDirectory(); + NSString* directoryPath = [temporaryDirectory stringByAppendingPathComponent:@"ort-objective-c-test"]; + + NSError* error = nil; + [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath + withIntermediateDirectories:YES + attributes:nil + error:&error]; + + XCTAssertNil(error, @"Error creating temporary directory: %@", error.localizedDescription); + + // add teardown block to delete the temporary directory + [testCase addTeardownBlock:^{ + NSError* error = nil; + [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error]; + XCTAssertNil(error, @"Error removing temporary directory: %@", error.localizedDescription); + }]; + + return directoryPath; +} + +NSArray* getFloatArrayFromData(NSData* data) { + NSMutableArray* array = [NSMutableArray array]; + float value; + for (size_t i = 0; i < data.length / sizeof(float); ++i) { + [data getBytes:&value range:NSMakeRange(i * sizeof(float), sizeof(float))]; + [array addObject:[NSNumber numberWithFloat:value]]; + } + return array; +} + +} // namespace test_utils + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh new file mode 100755 index 0000000..0a58ca8 --- /dev/null +++ b/objectivec/test/testdata/gen_models.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Get directory this script is in +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd ${DIR} + +python3 ./single_add_gen.py + +ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort new file mode 100644 index 0000000000000000000000000000000000000000..f622784b35366ea8f0c33ccbdb513b5d6f7df7c1 GIT binary patch literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx new file mode 100644 index 0000000000000000000000000000000000000000..82e8fe669e0d84b6111f678b0742a552d820269b GIT binary patch literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py new file mode 100644 index 0000000..15b4372 --- /dev/null +++ b/objectivec/test/testdata/single_add_gen.py @@ -0,0 +1,19 @@ +import onnx +from onnx import TensorProto, helper + +graph = helper.make_graph( + [ # nodes + helper.make_node("Add", ["A", "B"], ["C"], "Add"), + ], + "SingleAdd", # name + [ # inputs + helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), + helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), + ], + [ # outputs + helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), + ], +) + +model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) +onnx.save(model, r"single_add.onnx") diff --git a/swift/.DS_Store b/swift/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..f42f1cf4750f83663b0b9f590b707e97ea259a51 GIT binary patch literal 6148 zcmeHKyH3ME5S)b+k!Vt;ykE#4oUBks0zLo{M+hl6g%gR=9ly=&gD92*B?a1*cE`8g zxzkPI^#YLQ)UJR9fH_?epBkp7@6{)E6B!}WxyJ)e=y1dv-Y3=96Utp;Lso~65r2n< z`*dh6zM{tyc8o{#ZNJ^W91i>ITV^&DNCi@XR3H^d1%6RLdoOK%=a?}SNCi@XvjX~k zD0IadI5^s;gTY1s;*4oCKHDroESezJz`>CjnmCo{REZHooX&iSx*9k*IvoxNf~-a5IQ_S!;! srhgl2t(?JHG0|Ev7ut%K7j;FS`Mw4Yjz(wR=*0XHP+ihefxl4T3q58UfB*mh literal 0 HcmV?d00001 diff --git a/swift/OnnxRuntimeBindingsTests/.DS_Store b/swift/OnnxRuntimeBindingsTests/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2669ebf3d77440c8d1f59febf92f2a487412ef29 GIT binary patch literal 6148 zcmeHKF=_)r43rWV4sKkg+%NbCi*Y_+e;~w8XE?BNe^uUzna$xu`(T(FpVKGyP#Fip@s5j~Y;W&&KAb1j_Y>qk*_Ip|zVr9T zw_!NmCn+lhq<|EV0#ZN<{8|C_Uf6t*s3--bfE2hY!0$tY6MNy97@rP=7y*DYq{Fa| zSpwLY0QSN$5gC{#6_`}75yO*?e5<-%I3_0DyoL|2lf5PskJIt~7UkwWQBev=fm;P0 zbGu~!e}Vrn|KF0dlLAuUUn$_T&2F>Cm8!Q+F2`Qm;IDAje8Op12L&P8F)-ROHf+bw cQIvI!Ydr6TV`9*e4?0jk1Jp$(1^!xrFAN41od5s; literal 0 HcmV?d00001 diff --git a/swift/OnnxRuntimeBindingsTests/Resources/single_add.basic.ort b/swift/OnnxRuntimeBindingsTests/Resources/single_add.basic.ort new file mode 100644 index 0000000000000000000000000000000000000000..f622784b35366ea8f0c33ccbdb513b5d6f7df7c1 GIT binary patch literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI literal 0 HcmV?d00001 diff --git a/swift/OnnxRuntimeBindingsTests/SwiftOnnxRuntimeBindingsTests.swift b/swift/OnnxRuntimeBindingsTests/SwiftOnnxRuntimeBindingsTests.swift new file mode 100644 index 0000000..48e2764 --- /dev/null +++ b/swift/OnnxRuntimeBindingsTests/SwiftOnnxRuntimeBindingsTests.swift @@ -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) + } + } +} From 37d33c894103a59b52c0e7887c3cdd5da82f713f Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 10:59:13 -0700 Subject: [PATCH 03/70] exclude test/ --- objectivec/test/assert_arc_enabled.mm | 4 - objectivec/test/assertion_utils.h | 46 --- objectivec/test/ort_checkpoint_test.mm | 117 ------ objectivec/test/ort_env_test.mm | 30 -- objectivec/test/ort_session_test.mm | 264 ------------- objectivec/test/ort_training_session_test.mm | 359 ------------------ objectivec/test/ort_training_utils_test.mm | 26 -- objectivec/test/ort_value_test.mm | 79 ---- objectivec/test/test_utils.h | 21 - objectivec/test/test_utils.mm | 44 --- objectivec/test/testdata/gen_models.sh | 12 - objectivec/test/testdata/single_add.basic.ort | Bin 1296 -> 0 bytes objectivec/test/testdata/single_add.onnx | Bin 93 -> 0 bytes objectivec/test/testdata/single_add_gen.py | 19 - 14 files changed, 1021 deletions(-) delete mode 100644 objectivec/test/assert_arc_enabled.mm delete mode 100644 objectivec/test/assertion_utils.h delete mode 100644 objectivec/test/ort_checkpoint_test.mm delete mode 100644 objectivec/test/ort_env_test.mm delete mode 100644 objectivec/test/ort_session_test.mm delete mode 100644 objectivec/test/ort_training_session_test.mm delete mode 100644 objectivec/test/ort_training_utils_test.mm delete mode 100644 objectivec/test/ort_value_test.mm delete mode 100644 objectivec/test/test_utils.h delete mode 100644 objectivec/test/test_utils.mm delete mode 100755 objectivec/test/testdata/gen_models.sh delete mode 100644 objectivec/test/testdata/single_add.basic.ort delete mode 100644 objectivec/test/testdata/single_add.onnx delete mode 100644 objectivec/test/testdata/single_add_gen.py diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm deleted file mode 100644 index 9aa0bad..0000000 --- a/objectivec/test/assert_arc_enabled.mm +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h deleted file mode 100644 index 2b72435..0000000 --- a/objectivec/test/assertion_utils.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -NS_ASSUME_NONNULL_BEGIN - -#define ORTAssertNullableResultSuccessful(result, error) \ - do { \ - XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertBoolResultSuccessful(result, error) \ - do { \ - XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertNullableResultUnsuccessful(result, error) \ - do { \ - XCTAssertNil(result); \ - XCTAssertNotNil(error); \ - } while (0) - -#define ORTAssertBoolResultUnsuccessful(result, error) \ - do { \ - XCTAssertFalse(result); \ - XCTAssertNotNil(error); \ - } while (0) - -#define ORTAssertEqualFloatAndNoError(expected, result, error) \ - do { \ - XCTAssertEqualWithAccuracy(expected, result, 1e-3f, @"Expected %f but got %f. Error:%@", expected, result, error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertEqualFloatArrays(expected, result) \ - do { \ - XCTAssertEqual(expected.count, result.count); \ - for (size_t i = 0; i < expected.count; ++i) { \ - XCTAssertEqualWithAccuracy([expected[i] floatValue], [result[i] floatValue], 1e-3f); \ - } \ - } while (0) - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_checkpoint_test.mm b/objectivec/test/ort_checkpoint_test.mm deleted file mode 100644 index 9b2196f..0000000 --- a/objectivec/test/ort_checkpoint_test.mm +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_checkpoint.h" -#import "ort_training_session.h" -#import "ort_env.h" -#import "ort_session.h" - -#import "test/test_utils.h" -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTCheckpointTest : XCTestCase -@property(readonly, nullable) ORTEnv* ortEnv; -@end - -@implementation ORTCheckpointTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - - NSError* err = nil; - _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(_ortEnv, err); -} - -+ (NSString*)getCheckpointPath { - NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; - NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"checkpoint.ckpt"]; - return path; -} - -+ (NSString*)getTrainingModelPath { - NSBundle* bundle = [NSBundle bundleForClass:[ORTCheckpointTest class]]; - NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:@"training_model.onnx"]; - return path; -} - -- (void)testSaveCheckpoint { - NSError* error = nil; - ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; - ORTAssertNullableResultSuccessful(checkpoint, error); - - // save checkpoint - NSString* path = [test_utils::createTemporaryDirectory(self) stringByAppendingPathComponent:@"save_checkpoint.ckpt"]; - XCTAssertNotNil(path); - BOOL result = [checkpoint saveCheckpointToPath:path withOptimizerState:NO error:&error]; - - ORTAssertBoolResultSuccessful(result, error); -} - -- (void)testInitCheckpoint { - NSError* error = nil; - ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; - ORTAssertNullableResultSuccessful(checkpoint, error); -} - -- (void)testIntProperty { - NSError* error = nil; - // Load checkpoint - ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; - ORTAssertNullableResultSuccessful(checkpoint, error); - - // Add property - BOOL result = [checkpoint addIntPropertyWithName:@"test" value:314 error:&error]; - ORTAssertBoolResultSuccessful(result, error); - - // Get property - int64_t value = [checkpoint getIntPropertyWithName:@"test" error:&error]; - XCTAssertEqual(value, 314); -} - -- (void)testFloatProperty { - NSError* error = nil; - // Load checkpoint - ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; - ORTAssertNullableResultSuccessful(checkpoint, error); - - // Add property - BOOL result = [checkpoint addFloatPropertyWithName:@"test" value:3.14f error:&error]; - ORTAssertBoolResultSuccessful(result, error); - - // Get property - float value = [checkpoint getFloatPropertyWithName:@"test" error:&error]; - XCTAssertEqual(value, 3.14f); -} - -- (void)testStringProperty { - NSError* error = nil; - // Load checkpoint - ORTCheckpoint* checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTCheckpointTest getCheckpointPath] error:&error]; - ORTAssertNullableResultSuccessful(checkpoint, error); - - // Add property - BOOL result = [checkpoint addStringPropertyWithName:@"test" value:@"hello" error:&error]; - ORTAssertBoolResultSuccessful(result, error); - - // Get property - NSString* value = [checkpoint getStringPropertyWithName:@"test" error:&error]; - XCTAssertEqualObjects(value, @"hello"); -} - -- (void)tearDown { - _ortEnv = nil; - - [super tearDown]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm deleted file mode 100644 index 420f55f..0000000 --- a/objectivec/test/ort_env_test.mm +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_env.h" - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTEnvTest : XCTestCase -@end - -@implementation ORTEnvTest -- (void)testGetOrtVersion { - NSString* ver = ORTVersion(); - XCTAssertNotNil(ver); -} - -- (void)testInitOk { - NSError* err = nil; - ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(env, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm deleted file mode 100644 index 57b92fd..0000000 --- a/objectivec/test/ort_session_test.mm +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_coreml_execution_provider.h" -#import "ort_xnnpack_execution_provider.h" -#import "ort_env.h" -#import "ort_session.h" -#import "ort_value.h" - -#import "test/assertion_utils.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTSessionTest : XCTestCase - -@property(readonly, nullable) ORTEnv* ortEnv; - -@end - -@implementation ORTSessionTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - - NSError* err = nil; - _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(_ortEnv, err); -} - -- (void)tearDown { - _ortEnv = nil; - - [super tearDown]; -} - -// model with an Add op -// inputs: A, B -// output: C = A + B -+ (NSString*)getAddModelPath { - NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; - NSString* path = [bundle pathForResource:@"single_add.basic" - ofType:@"ort"]; - return path; -} - -+ (NSMutableData*)dataWithScalarFloat:(float)value { - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; - return data; -} - -+ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { - NSArray* shape = @[ @1 ]; - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeFloat - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - return ortValue; -} - -+ (ORTSessionOptions*)makeSessionOptions { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(sessionOptions, err); - return sessionOptions; -} - -+ (ORTRunOptions*)makeRunOptions { - NSError* err = nil; - ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(runOptions, err); - return runOptions; -} - -- (void)testInitAndRunWithPreallocatedOutputOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultSuccessful(runResult, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testInitAndRunOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSDictionary* outputs = - [session runWithInputs:@{@"A" : a, @"B" : b} - outputNames:[NSSet setWithArray:@[ @"C" ]] - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertNullableResultSuccessful(outputs, err); - - ORTValue* cOutput = outputs[@"C"]; - XCTAssertNotNil(cOutput); - - NSData* cData = [cOutput tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(cData, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testGetNamesOk { - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSArray* inputNames = [session inputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(inputNames, err); - XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); - - NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; - ORTAssertNullableResultSuccessful(overridableInitializerNames, err); - XCTAssertEqualObjects(overridableInitializerNames, (@[])); - - NSArray* outputNames = [session outputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(outputNames, err); - XCTAssertEqualObjects(outputNames, (@[ @"C" ])); -} - -- (void)testInitFailsWithInvalidPath { - NSString* invalidModelPath = @"invalid/path/to/model.ort"; - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:invalidModelPath - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultUnsuccessful(session, err); -} - -- (void)testRunFailsWithInvalidInput { - NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"D" : d} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultUnsuccessful(runResult, err); -} - -- (void)testAppendCoreMLEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; - coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option - - BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions - error:&err]; - - if (!ORTIsCoreMLExecutionProviderAvailable()) { - ORTAssertBoolResultUnsuccessful(appendResult, err); - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} - -- (void)testAppendXnnpackEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; - XnnpackOptions.intra_op_num_threads = 2; - - BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions - error:&err]; - // Without xnnpack EP in building also can pass the test - NSString* err_msg = [err localizedDescription]; - if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} - -static bool gDummyRegisterCustomOpsFnCalled = false; - -static OrtStatus* _Nullable DummyRegisterCustomOpsFn(OrtSessionOptions* /*session_options*/, - const OrtApiBase* /*api*/) { - gDummyRegisterCustomOpsFnCalled = true; - return nullptr; -} - -- (void)testRegisterCustomOpsUsingFunctionPointer { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - - gDummyRegisterCustomOpsFnCalled = false; - BOOL registerResult = [sessionOptions registerCustomOpsUsingFunctionPointer:&DummyRegisterCustomOpsFn - error:&err]; - ORTAssertBoolResultSuccessful(registerResult, err); - - XCTAssertEqual(gDummyRegisterCustomOpsFnCalled, true); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_session_test.mm b/objectivec/test/ort_training_session_test.mm deleted file mode 100644 index 683965d..0000000 --- a/objectivec/test/ort_training_session_test.mm +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_checkpoint.h" -#import "ort_training_session.h" -#import "ort_env.h" -#import "ort_session.h" -#import "ort_value.h" - -#import "test/test_utils.h" -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTTrainingSessionTest : XCTestCase -@property(readonly, nullable) ORTEnv* ortEnv; -@property(readonly, nullable) ORTCheckpoint* checkpoint; -@property(readonly, nullable) ORTTrainingSession* session; -@end - -@implementation ORTTrainingSessionTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - - NSError* err = nil; - _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(_ortEnv, err); - _checkpoint = [[ORTCheckpoint alloc] initWithPath:[ORTTrainingSessionTest - getFilePathFromName:@"checkpoint.ckpt"] - error:&err]; - ORTAssertNullableResultSuccessful(_checkpoint, err); - _session = [self makeTrainingSessionWithCheckpoint:_checkpoint]; -} - -+ (NSString*)getFilePathFromName:(NSString*)name { - NSBundle* bundle = [NSBundle bundleForClass:[ORTTrainingSessionTest class]]; - NSString* path = [[bundle resourcePath] stringByAppendingPathComponent:name]; - return path; -} - -+ (NSMutableData*)loadTensorDataFromFile:(NSString*)filePath skipHeader:(BOOL)skipHeader { - NSError* error = nil; - NSString* fileContents = [NSString stringWithContentsOfFile:filePath - encoding:NSUTF8StringEncoding - error:&error]; - ORTAssertNullableResultSuccessful(fileContents, error); - - NSArray* lines = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; - - if (skipHeader) { - lines = [lines subarrayWithRange:NSMakeRange(1, lines.count - 1)]; - } - - NSArray* dataArray = [lines[0] componentsSeparatedByCharactersInSet: - [NSCharacterSet characterSetWithCharactersInString:@",[] "]]; - NSMutableData* tensorData = [NSMutableData data]; - - for (NSString* str in dataArray) { - if (str.length > 0) { - float value = [str floatValue]; - [tensorData appendBytes:&value length:sizeof(float)]; - } - } - - return tensorData; -} - -- (ORTTrainingSession*)makeTrainingSessionWithCheckpoint:(ORTCheckpoint*)checkpoint { - NSError* error = nil; - ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&error]; - ORTAssertNullableResultSuccessful(sessionOptions, error); - - ORTTrainingSession* session = [[ORTTrainingSession alloc] - initWithEnv:self.ortEnv - sessionOptions:sessionOptions - checkpoint:checkpoint - trainModelPath:[ORTTrainingSessionTest getFilePathFromName:@"training_model.onnx"] - evalModelPath:[ORTTrainingSessionTest getFilePathFromName:@"eval_model.onnx"] - optimizerModelPath:[ORTTrainingSessionTest getFilePathFromName:@"adamw.onnx"] - error:&error]; - - ORTAssertNullableResultSuccessful(session, error); - return session; -} - -- (void)testInitTrainingSession { - NSError* error = nil; - - // check that inputNames contains input-0 - NSArray* inputNames = [self.session getTrainInputNamesWithError:&error]; - ORTAssertNullableResultSuccessful(inputNames, error); - - XCTAssertTrue(inputNames.count > 0); - XCTAssertTrue([inputNames containsObject:@"input-0"]); - - // check that outNames contains onnx::loss::21273 - NSArray* outputNames = [self.session getTrainOutputNamesWithError:&error]; - ORTAssertNullableResultSuccessful(outputNames, error); - - XCTAssertTrue(outputNames.count > 0); - XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); -} - -- (void)testInitTrainingSessionWithEval { - NSError* error = nil; - - // check that inputNames contains input-0 - NSArray* inputNames = [self.session getEvalInputNamesWithError:&error]; - ORTAssertNullableResultSuccessful(inputNames, error); - - XCTAssertTrue(inputNames.count > 0); - XCTAssertTrue([inputNames containsObject:@"input-0"]); - - // check that outNames contains onnx::loss::21273 - NSArray* outputNames = [self.session getEvalOutputNamesWithError:&error]; - ORTAssertNullableResultSuccessful(outputNames, error); - - XCTAssertTrue(outputNames.count > 0); - XCTAssertTrue([outputNames containsObject:@"onnx::loss::21273"]); -} - -- (void)runTrainStep { - // load input and expected output - NSError* error = nil; - NSMutableData* expectedOutput = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest - getFilePathFromName:@"loss_1.out"] - skipHeader:YES]; - - NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest - getFilePathFromName:@"input-0.in"] - skipHeader:YES]; - - int32_t labels[] = {1, 1}; - - // create ORTValue array for input and labels - NSMutableArray* inputValues = [NSMutableArray array]; - - ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input - elementType:ORTTensorElementDataTypeFloat - shape:@[ @2, @784 ] - error:&error]; - ORTAssertNullableResultSuccessful(inputTensor, error); - [inputValues addObject:inputTensor]; - - ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels - length:sizeof(labels)] - elementType:ORTTensorElementDataTypeInt32 - shape:@[ @2 ] - error:&error]; - - ORTAssertNullableResultSuccessful(labelTensor, error); - [inputValues addObject:labelTensor]; - - NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; - ORTAssertNullableResultSuccessful(outputs, error); - XCTAssertTrue(outputs.count > 0); - - BOOL result = [self.session lazyResetGradWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - - outputs = [self.session trainStepWithInputValues:inputValues error:&error]; - ORTAssertNullableResultSuccessful(outputs, error); - XCTAssertTrue(outputs.count > 0); - - ORTValue* outputValue = outputs[0]; - ORTValueTypeInfo* typeInfo = [outputValue typeInfoWithError:&error]; - ORTAssertNullableResultSuccessful(typeInfo, error); - XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); - XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); - - ORTTensorTypeAndShapeInfo* tensorInfo = [outputValue tensorTypeAndShapeInfoWithError:&error]; - ORTAssertNullableResultSuccessful(tensorInfo, error); - XCTAssertEqual(tensorInfo.elementType, ORTTensorElementDataTypeFloat); - - NSMutableData* tensorData = [outputValue tensorDataWithError:&error]; - ORTAssertNullableResultSuccessful(tensorData, error); - ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(tensorData), - test_utils::getFloatArrayFromData(expectedOutput)); -} - -- (void)testTrainStepOutput { - [self runTrainStep]; -} - -- (void)testOptimizerStep { - // load input and expected output - NSError* error = nil; - NSMutableData* expectedOutput1 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest - getFilePathFromName:@"loss_1.out"] - skipHeader:YES]; - - NSMutableData* expectedOutput2 = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest - getFilePathFromName:@"loss_2.out"] - skipHeader:YES]; - - NSMutableData* input = [ORTTrainingSessionTest loadTensorDataFromFile:[ORTTrainingSessionTest - getFilePathFromName:@"input-0.in"] - skipHeader:YES]; - - int32_t labels[] = {1, 1}; - - // create ORTValue array for input and labels - NSMutableArray* inputValues = [NSMutableArray array]; - - ORTValue* inputTensor = [[ORTValue alloc] initWithTensorData:input - elementType:ORTTensorElementDataTypeFloat - shape:@[ @2, @784 ] - error:&error]; - ORTAssertNullableResultSuccessful(inputTensor, error); - [inputValues addObject:inputTensor]; - - ORTValue* labelTensor = [[ORTValue alloc] initWithTensorData:[NSMutableData dataWithBytes:labels - length:sizeof(labels)] - elementType:ORTTensorElementDataTypeInt32 - shape:@[ @2 ] - error:&error]; - ORTAssertNullableResultSuccessful(labelTensor, error); - [inputValues addObject:labelTensor]; - - // run train step, optimizer steps and check loss - NSArray* outputs = [self.session trainStepWithInputValues:inputValues error:&error]; - ORTAssertNullableResultSuccessful(outputs, error); - - NSMutableData* loss = [outputs[0] tensorDataWithError:&error]; - ORTAssertNullableResultSuccessful(loss, error); - ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), - test_utils::getFloatArrayFromData(expectedOutput1)); - - BOOL result = [self.session lazyResetGradWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - - outputs = [self.session trainStepWithInputValues:inputValues error:&error]; - ORTAssertNullableResultSuccessful(outputs, error); - - loss = [outputs[0] tensorDataWithError:&error]; - ORTAssertNullableResultSuccessful(loss, error); - ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), - test_utils::getFloatArrayFromData(expectedOutput1)); - - result = [self.session optimizerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - - outputs = [self.session trainStepWithInputValues:inputValues error:&error]; - ORTAssertNullableResultSuccessful(outputs, error); - loss = [outputs[0] tensorDataWithError:&error]; - ORTAssertNullableResultSuccessful(loss, error); - ORTAssertEqualFloatArrays(test_utils::getFloatArrayFromData(loss), - test_utils::getFloatArrayFromData(expectedOutput2)); -} - -- (void)testSetLearningRate { - NSError* error = nil; - - float learningRate = 0.1f; - BOOL result = [self.session setLearningRate:learningRate error:&error]; - ORTAssertBoolResultSuccessful(result, error); - - float actualLearningRate = [self.session getLearningRateWithError:&error]; - ORTAssertEqualFloatAndNoError(learningRate, actualLearningRate, error); -} - -- (void)testLinearLRScheduler { - NSError* error = nil; - - float learningRate = 0.1f; - BOOL result = [self.session registerLinearLRSchedulerWithWarmupStepCount:2 - totalStepCount:4 - initialLr:learningRate - error:&error]; - - ORTAssertBoolResultSuccessful(result, error); - - [self runTrainStep]; - - result = [self.session optimizerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - result = [self.session schedulerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); - - result = [self.session optimizerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - result = [self.session schedulerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - ORTAssertEqualFloatAndNoError(0.1f, [self.session getLearningRateWithError:&error], error); - - result = [self.session optimizerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - result = [self.session schedulerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - ORTAssertEqualFloatAndNoError(0.05f, [self.session getLearningRateWithError:&error], error); - - result = [self.session optimizerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - result = [self.session schedulerStepWithError:&error]; - ORTAssertBoolResultSuccessful(result, error); - ORTAssertEqualFloatAndNoError(0.0f, [self.session getLearningRateWithError:&error], error); -} - -- (void)testExportModelForInference { - NSError* error = nil; - - NSString* inferenceModelPath = [test_utils::createTemporaryDirectory(self) - stringByAppendingPathComponent:@"inference_model.onnx"]; - XCTAssertNotNil(inferenceModelPath); - - NSArray* graphOutputNames = [NSArray arrayWithObjects:@"output-0", nil]; - - BOOL result = [self.session exportModelForInferenceWithOutputPath:inferenceModelPath - graphOutputNames:graphOutputNames - error:&error]; - - ORTAssertBoolResultSuccessful(result, error); - XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:inferenceModelPath]); - - [self addTeardownBlock:^{ - NSError* error = nil; - [[NSFileManager defaultManager] removeItemAtPath:inferenceModelPath error:&error]; - }]; -} - -- (void)testToBuffer { - NSError* error = nil; - ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; - ORTAssertNullableResultSuccessful(buffer, error); - - ORTValueTypeInfo* typeInfo = [buffer typeInfoWithError:&error]; - ORTAssertNullableResultSuccessful(typeInfo, error); - XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); - XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); -} - -- (void)testFromBuffer { - NSError* error = nil; - - ORTValue* buffer = [self.session toBufferWithTrainable:YES error:&error]; - ORTAssertNullableResultSuccessful(buffer, error); - - BOOL result = [self.session fromBufferWithValue:buffer error:&error]; - ORTAssertBoolResultSuccessful(result, error); -} - -- (void)tearDown { - _session = nil; - _checkpoint = nil; - _ortEnv = nil; - - [super tearDown]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_training_utils_test.mm b/objectivec/test/ort_training_utils_test.mm deleted file mode 100644 index 1695ddc..0000000 --- a/objectivec/test/ort_training_utils_test.mm +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import -#import "ort_training_session.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTTrainingUtilsTest : XCTestCase -@end - -@implementation ORTTrainingUtilsTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)testSetSeed { - ORTSetSeed(2718); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm deleted file mode 100644 index 734ad39..0000000 --- a/objectivec/test/ort_value_test.mm +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_value.h" - -#include - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTValueTest : XCTestCase -@end - -@implementation ORTValueTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)testInitTensorOk { - int32_t value = 42; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value - length:sizeof(int32_t)]; - NSArray* shape = @[ @1 ]; - - const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:elementType - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - - auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { - XCTAssertEqual(tensorInfo.elementType, elementType); - XCTAssertEqualObjects(tensorInfo.shape, shape); - }; - - ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(typeInfo, err); - XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); - XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); - checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); - - ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(tensorInfo, err); - checkTensorInfo(tensorInfo); - - NSData* actualData = [ortValue tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(actualData, err); - XCTAssertEqual(actualData.length, sizeof(int32_t)); - int32_t actualValue; - memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); - XCTAssertEqual(actualValue, value); -} - -- (void)testInitTensorFailsWithDataSmallerThanShape { - std::vector values{1, 2, 3, 4}; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() - length:values.size() * sizeof(int32_t)]; - NSArray* shape = @[ @2, @3 ]; // too large - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeInt32 - shape:shape - error:&err]; - ORTAssertNullableResultUnsuccessful(ortValue, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.h b/objectivec/test/test_utils.h deleted file mode 100644 index 8a5e6e4..0000000 --- a/objectivec/test/test_utils.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import -#import - -#import "ort_session.h" -#import "ort_env.h" -#import "ort_value.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace test_utils { - -NSString* _Nullable createTemporaryDirectory(XCTestCase* testCase); - -NSArray* getFloatArrayFromData(NSData* data); - -} // namespace test_utils - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/test_utils.mm b/objectivec/test/test_utils.mm deleted file mode 100644 index ef8e8c5..0000000 --- a/objectivec/test/test_utils.mm +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "test_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -namespace test_utils { - -NSString* createTemporaryDirectory(XCTestCase* testCase) { - NSString* temporaryDirectory = NSTemporaryDirectory(); - NSString* directoryPath = [temporaryDirectory stringByAppendingPathComponent:@"ort-objective-c-test"]; - - NSError* error = nil; - [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath - withIntermediateDirectories:YES - attributes:nil - error:&error]; - - XCTAssertNil(error, @"Error creating temporary directory: %@", error.localizedDescription); - - // add teardown block to delete the temporary directory - [testCase addTeardownBlock:^{ - NSError* error = nil; - [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error]; - XCTAssertNil(error, @"Error removing temporary directory: %@", error.localizedDescription); - }]; - - return directoryPath; -} - -NSArray* getFloatArrayFromData(NSData* data) { - NSMutableArray* array = [NSMutableArray array]; - float value; - for (size_t i = 0; i < data.length / sizeof(float); ++i) { - [data getBytes:&value range:NSMakeRange(i * sizeof(float), sizeof(float))]; - [array addObject:[NSNumber numberWithFloat:value]]; - } - return array; -} - -} // namespace test_utils - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh deleted file mode 100755 index 0a58ca8..0000000 --- a/objectivec/test/testdata/gen_models.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -# Get directory this script is in -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -cd ${DIR} - -python3 ./single_add_gen.py - -ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort deleted file mode 100644 index f622784b35366ea8f0c33ccbdb513b5d6f7df7c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx deleted file mode 100644 index 82e8fe669e0d84b6111f678b0742a552d820269b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py deleted file mode 100644 index 15b4372..0000000 --- a/objectivec/test/testdata/single_add_gen.py +++ /dev/null @@ -1,19 +0,0 @@ -import onnx -from onnx import TensorProto, helper - -graph = helper.make_graph( - [ # nodes - helper.make_node("Add", ["A", "B"], ["C"], "Add"), - ], - "SingleAdd", # name - [ # inputs - helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), - helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), - ], - [ # outputs - helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), - ], -) - -model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) -onnx.save(model, r"single_add.onnx") From 354f6a56e4eb45515154318858603929b243e24f Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 11:02:44 -0700 Subject: [PATCH 04/70] exclude some objc files --- objectivec/include/onnxruntime_training.h | 9 - objectivec/include/ort_checkpoint.h | 119 ---------- objectivec/include/ort_training_session.h | 263 --------------------- objectivec/ort_checkpoint.mm | 111 --------- objectivec/ort_checkpoint_internal.h | 16 -- objectivec/ort_training_session.mm | 224 ------------------ objectivec/ort_training_session_internal.h | 16 -- 7 files changed, 758 deletions(-) delete mode 100644 objectivec/include/onnxruntime_training.h delete mode 100644 objectivec/include/ort_checkpoint.h delete mode 100644 objectivec/include/ort_training_session.h delete mode 100644 objectivec/ort_checkpoint.mm delete mode 100644 objectivec/ort_checkpoint_internal.h delete mode 100644 objectivec/ort_training_session.mm delete mode 100644 objectivec/ort_training_session_internal.h diff --git a/objectivec/include/onnxruntime_training.h b/objectivec/include/onnxruntime_training.h deleted file mode 100644 index 504447e..0000000 --- a/objectivec/include/onnxruntime_training.h +++ /dev/null @@ -1,9 +0,0 @@ -// 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" diff --git a/objectivec/include/ort_checkpoint.h b/objectivec/include/ort_checkpoint.h deleted file mode 100644 index 85e5844..0000000 --- a/objectivec/include/ort_checkpoint.h +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import -#include - -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 diff --git a/objectivec/include/ort_training_session.h b/objectivec/include/ort_training_session.h deleted file mode 100644 index 15c0137..0000000 --- a/objectivec/include/ort_training_session.h +++ /dev/null @@ -1,263 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import -#include - -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*)trainStepWithInputValues:(NSArray*)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*)evalStepWithInputValues:(NSArray*)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*)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*)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*)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*)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*)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 diff --git a/objectivec/ort_checkpoint.mm b/objectivec/ort_checkpoint.mm deleted file mode 100644 index 1238645..0000000 --- a/objectivec/ort_checkpoint.mm +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_checkpoint_internal.h" - -#include -#include -#include -#import "cxx_api.h" - -#import "error_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation ORTCheckpoint { - std::optional _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(&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(&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(&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 diff --git a/objectivec/ort_checkpoint_internal.h b/objectivec/ort_checkpoint_internal.h deleted file mode 100644 index 3d1550c..0000000 --- a/objectivec/ort_checkpoint_internal.h +++ /dev/null @@ -1,16 +0,0 @@ -// 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 diff --git a/objectivec/ort_training_session.mm b/objectivec/ort_training_session.mm deleted file mode 100644 index 285151b..0000000 --- a/objectivec/ort_training_session.mm +++ /dev/null @@ -1,224 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_training_session_internal.h" - -#import -#import -#import - -#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 _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 evalPath = utils::toStdOptionalString(evalModelPath); - std::optional 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*)trainStepWithInputValues:(NSArray*)inputs - error:(NSError**)error { - try { - std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); - - size_t outputCount; - Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetTrainingModelOutputCount(*_session, &outputCount)); - std::vector 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*)evalStepWithInputValues:(NSArray*)inputs - error:(NSError**)error { - try { - // create vector of OrtValue from NSArray with same size as inputValues - std::vector inputValues = utils::getWrappedCAPIOrtValues(inputs); - - size_t outputCount; - Ort::ThrowOnError(Ort::GetTrainingApi().TrainingSessionGetEvalModelOutputCount(*_session, &outputCount)); - std::vector 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*)getTrainInputNamesWithError:(NSError**)error { - try { - std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(true); - return utils::toNSStringNSArray(inputNames); - } - ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) -} - -- (nullable NSArray*)getTrainOutputNamesWithError:(NSError**)error { - try { - std::vector outputNames = [self CXXAPIOrtTrainingSession].OutputNames(true); - return utils::toNSStringNSArray(outputNames); - } - ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) -} - -- (nullable NSArray*)getEvalInputNamesWithError:(NSError**)error { - try { - std::vector inputNames = [self CXXAPIOrtTrainingSession].InputNames(false); - return utils::toNSStringNSArray(inputNames); - } - ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) -} - -- (nullable NSArray*)getEvalOutputNamesWithError:(NSError**)error { - try { - std::vector 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*)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 diff --git a/objectivec/ort_training_session_internal.h b/objectivec/ort_training_session_internal.h deleted file mode 100644 index 453c941..0000000 --- a/objectivec/ort_training_session_internal.h +++ /dev/null @@ -1,16 +0,0 @@ -// 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 From 83a311e5f7ee543cc5f15cd4db30ad4ea68c2e7a Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 14:14:50 -0700 Subject: [PATCH 05/70] add initial test pipeline --- Package.swift | 16 +- cmake/deps.txt | 44 +++++ .../mac-ios-swift-packaging-pipeline.yml | 178 ++++++++++++++++++ .../github/scripts/install_protobuf.sh | 59 ++++++ ...t-governance-component-detection-steps.yml | 18 ++ .../github/templates/install-appcenter.yml | 12 ++ .../github/templates/use-xcode-version.yml | 14 ++ version.txt | 1 + 8 files changed, 334 insertions(+), 8 deletions(-) create mode 100644 cmake/deps.txt create mode 100644 tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml create mode 100644 tools/ci_build/github/scripts/install_protobuf.sh create mode 100644 tools/ci_build/github/templates/component-governance-component-detection-steps.yml create mode 100644 tools/ci_build/github/templates/install-appcenter.yml create mode 100644 tools/ci_build/github/templates/use-xcode-version.yml create mode 100644 version.txt diff --git a/Package.swift b/Package.swift index e053732..e7f008a 100644 --- a/Package.swift +++ b/Package.swift @@ -32,14 +32,14 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - exclude: ["test", "docs", "ReadMe.md", "format_objc.sh", - "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"], + // exclude: ["test", "docs", "ReadMe.md", "format_objc.sh", + // "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", diff --git a/cmake/deps.txt b/cmake/deps.txt new file mode 100644 index 0000000..63bdf21 --- /dev/null +++ b/cmake/deps.txt @@ -0,0 +1,44 @@ +#Name;Url;SHA1 +#This is a CSV file. +#The columns are separated by ";" because a list in cmake is just a ";" separated group of strings. +#Names should be in lower case. They will be used as variable names in cmake. +#URLs can be either https URLs or local file paths in cmake-style(directory separator is a forward slash character). +#SHA1 hashes can be generated by running sha1sum command. +#If you need to change abseil's version to a different one, you may also want to update external\abseil-cpp.natvis +#since the file contains a version string: "lts_20220623". However, the file is for debugging purposes only and would +#not affect built binaries. +abseil_cpp;https://github.com/abseil/abseil-cpp/archive/refs/tags/20220623.1.zip;50c137c88965cba015dfcc8fd5d9b46d23146751 +cxxopts;https://github.com/jarro2783/cxxopts/archive/3c73d91c0b04e2b59462f0a741be8c07024c1bc0.zip;6c6ca7f8480b26c8d00476e0e24b7184717fe4f0 +date;https://github.com/HowardHinnant/date/archive/refs/tags/v2.4.1.zip;ea99f021262b1d804a872735c658860a6a13cc98 +dlpack;https://github.com/dmlc/dlpack/archive/refs/tags/v0.6.zip;4d565dd2e5b31321e5549591d78aa7f377173445 +flatbuffers;https://github.com/google/flatbuffers/archive/refs/tags/v1.12.0.zip;ba0a75fd12dbef8f6557a74e611b7a3d0c5fe7bf +fp16;https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip;b985f6985a05a1c03ff1bb71190f66d8f98a1494 +fxdiv;https://github.com/Maratyszcza/FXdiv/archive/63058eff77e11aa15bf531df5dd34395ec3017c8.zip;a5658f4036402dbca7cebee32be57fb8149811e1 +google_benchmark;https://github.com/google/benchmark/archive/refs/tags/v1.7.0.zip;e97c368b176e8614e3f1bf13dd9abcf6a7ad9908 +google_nsync;https://github.com/google/nsync/archive/refs/tags/1.23.0.zip;f3233450cf7156fc0bedd1b0e884eddec264897c +googletest;https://github.com/google/googletest/archive/519beb0e52c842729b4b53731d27c0e0c32ab4a2.zip;4b3c37972e4c1bef1185d46f702082f8772ee73f +googlexnnpack;https://github.com/google/XNNPACK/archive/003c580e696a774afdc984996ee909b7c8d8128c.zip;9f192e3f15e1e37ae9c78d53eeea47e45c5eb31c +json;https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip;f257f8dc27c5b8c085dc887b40cddd18ae1f725c +microsoft_gsl;https://github.com/microsoft/GSL/archive/refs/tags/v4.0.0.zip;cf368104cd22a87b4dd0c80228919bb2df3e2a14 +microsoft_wil;https://github.com/microsoft/wil/archive/5f4caba4e7a9017816e47becdd918fcc872039ba.zip;fd119887d0d17c37adf1fc227b054befa28158ad +mimalloc;https://github.com/microsoft/mimalloc/archive/refs/tags/v2.1.1.zip;d5ee7d34223d0567892db5179849939c8769dc41 +mp11;https://github.com/boostorg/mp11/archive/refs/tags/boost-1.79.0.zip;c8f04e378535ededbe5af52c8f969d2dedbe73d5 +onnx;https://github.com/onnx/onnx/archive/refs/tags/v1.14.0.zip;3c6e43a36f94addc15afe939860127a1d74a9488 +#use the last commit of 8.6-GA branch (https://github.com/onnx/onnx-tensorrt/commit/6ba67d3428e05f690145373ca87fb8d32f98df45) +onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/6ba67d3428e05f690145373ca87fb8d32f98df45.zip;805902b4f03f09f07151e03b5ccc49968c9cc896 +protobuf;https://github.com/protocolbuffers/protobuf/archive/refs/tags/v21.12.zip;7cf2733949036c7d52fda017badcab093fe73bfa +protoc_win64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win64.zip;b4521f7ada5b260380f94c4bd7f1b7684c76969a +protoc_win32;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win32.zip;3688010318192c46ce73213cdfb6b3e5656da874 +protoc_linux_x64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip;338462004aa5be9fba45b35b5b4be43f69b47a90 +protoc_linux_x86;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_32.zip;61fdbe7d6360e065ec6fea23bca2cca673115fb8 +protoc_linux_aarch64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-aarch_64.zip;df9d45470b0b8cf939dd2f0ec6b88e9cafc4d617 +psimd;https://github.com/Maratyszcza/psimd/archive/072586a71b55b7f8c584153d223e95687148a900.zip;1f5454b01f06f9656b77e4a5e2e31d7422487013 +pthreadpool;https://github.com/Maratyszcza/pthreadpool/archive/1787867f6183f056420e532eec640cba25efafea.zip;e43e80781560c5ab404a4da20f34d846f5f5d101 +pybind11;https://github.com/pybind/pybind11/archive/refs/tags/v2.10.1.zip;769b6aa67a77f17a770960f604b727645b6f6a13 +pytorch_cpuinfo;https://github.com/pytorch/cpuinfo/archive/5916273f79a21551890fd3d56fc5375a78d1598d.zip;2be4d2ae321fada97cb39eaf4eeba5f8c85597cf +re2;https://github.com/google/re2/archive/refs/tags/2022-06-01.zip;aa77313b76e91b531ee7f3e45f004c6a502a5374 +safeint;https://github.com/dcleblanc/SafeInt/archive/ff15c6ada150a5018c5ef2172401cb4529eac9c0.zip;913a4046e5274d329af2806cb53194f617d8c0ab +tensorboard;https://github.com/tensorflow/tensorboard/archive/373eb09e4c5d2b3cc2493f0949dc4be6b6a45e81.zip;67b833913605a4f3f499894ab11528a702c2b381 +cutlass;https://github.com/NVIDIA/cutlass/archive/refs/tags/v3.0.0.zip;0f95b3c1fc1bd1175c4a90b2c9e39074d1bccefd +extensions;https://github.com/microsoft/onnxruntime-extensions/archive/94142d8391c9791ec71c38336436319a2d4ac7a0.zip;4365ac5140338b4cb75a39944a4be276e3829b3c +eigen;https://gitlab.com/libeigen/eigen/-/archive/3.4/eigen-3.4.zip;ee201b07085203ea7bd8eb97cbcb31b07cfa3efb \ No newline at end of file diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml new file mode 100644 index 0000000..c020be5 --- /dev/null +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -0,0 +1,178 @@ +parameters: +- name: BuildType + displayName: |- + Type of build. + "normal": A normal build not for publication. + type: string #TODO: add other build types name here + values: + - normal + default: normal + +name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format + +jobs: +- job: IosPackaging + displayName: "iOS Packaging" + + pool: + vmImage: "macOS-13" + + variables: + xcodeVersion: "14.3" + + timeoutInMinutes: 300 + + steps: + - task: InstallAppleCertificate@2 + inputs: + certSecureFile: '$(ios_signing_certificate_name)' + certPwd: '$(ios_signing_certificate_password)' + keychain: 'temp' + deleteCert: true + displayName: 'Install ORT Mobile Test Signing Certificate' + + - task: InstallAppleProvisioningProfile@1 + inputs: + provProfileSecureFile: '$(ios_provision_profile_name)' + removeProfile: true + displayName: 'Install ORT Mobile Test Provisioning Profile' + + - task: UsePythonVersion@0 + inputs: + versionSpec: "3.9" + addToPath: true + architecture: "x64" + + - template: templates/use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} + + # - template: templates/install-appcenter.yml + + - script: | + pip install -r tools/ci_build/github/apple/ios_packaging.requirements.txt + displayName: "Install Python requirements" + + - bash: | + set -e + + BUILD_TYPE="${{ parameters.BuildType }}" + VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + BASE_VERSION="$(cat "${VERSION_FILE}")" + SHORT_COMMIT_HASH="$(git rev-parse --short HEAD)" + DEV_VERSION="${BASE_VERSION}-dev+$(Build.BuildNumber).${SHORT_COMMIT_HASH}" + + case "${BUILD_TYPE}" in + ("normal") + VERSION="${DEV_VERSION}"; SHOULD_UPLOAD_ARCHIVES="false" ;; + (*) + echo "Invalid build type: ${BUILD_TYPE}"; exit 1 ;; + esac + + # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. + set +x + + set_var() { + local VAR_NAME=${1:?} + local VAR_VALUE=${2:?} + echo "##vso[task.setvariable variable=${VAR_NAME}]${VAR_VALUE}" + echo "${VAR_NAME}: ${VAR_VALUE}" + } + + set_var "ORT_POD_VERSION" "${VERSION}" + set_var "ORT_SHOULD_UPLOAD_ARCHIVES" "${SHOULD_UPLOAD_ARCHIVES}" + displayName: "Set variables" + + - script: | + $(Build.SourcesDirectory)/tools/ci_build/github/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt + displayName: "Build Host Protoc" + + # create and test full pods + - script: | + python tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ + --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ + --staging-dir "$(Build.BinariesDirectory)/staging" \ + --pod-version "${ORT_POD_VERSION}" \ + --test \ + --variant Full \ + --build-settings-file tools/ci_build/github/apple/default_full_ios_framework_build_settings.json \ + -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" + displayName: "[Full] Build iOS framework and assemble pod package files" + + - script: | + python tools/ci_build/github/apple/test_ios_packages.py \ + --fail_if_cocoapods_missing \ + --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ + --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ + --variant Full \ + --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_full" \ + --prepare_test_project_only + displayName: "[Full] Assemble test project for App Center" + + - task: Xcode@5 + inputs: + actions: 'build-for-testing' + configuration: 'Debug' + xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ios_package_test.xcworkspace' + sdk: 'iphoneos' + scheme: 'ios_package_test' + signingOption: 'manual' + signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' + provisioningProfileName: 'iOS Team Provisioning Profile' + args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData' + workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ + displayName: '[Full] Build iphone arm64 tests' + + # - script: | + # set -e -x + # appcenter test run xcuitest \ + # --app "AI-Frameworks/ORT-Mobile-iOS" \ + # --devices $(app_center_test_devices) \ + # --test-series "master" \ + # --locale "en_US" \ + # --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ + # --token $(app_center_api_token) + # displayName: "[Full] Run E2E tests on App Center" + + - task: AzureCLI@2 + inputs: + azureSubscription: 'AIInfraBuildOnnxRuntimeOSS' + scriptType: 'bash' + scriptLocation: 'scriptPath' + scriptPath: 'tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh' + arguments: >- + "$(Build.BinariesDirectory)/staging" + "$(Build.ArtifactStagingDirectory)" + "$(ORT_POD_VERSION)" + "$(ORT_SHOULD_UPLOAD_ARCHIVES)" + displayName: "Assemble artifacts" + + - script: | + set -e -x + ls -R "$(Build.ArtifactStagingDirectory)" + displayName: "List staged artifacts" + + - script: | + set -e -x + shasum -a 256 "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" + displayName: "Print ORT iOS Pod checksum" + + + # 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 + cp "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" + xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' + rm swift/pod-archive-onnxruntime-c-*.zip + displayName: "Test Package.swift usage" + + - publish: "$(Build.ArtifactStagingDirectory)" + artifact: ios_packaging_artifacts + displayName: "Publish artifacts" + + - template: templates/component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' diff --git a/tools/ci_build/github/scripts/install_protobuf.sh b/tools/ci_build/github/scripts/install_protobuf.sh new file mode 100644 index 0000000..b912b8e --- /dev/null +++ b/tools/ci_build/github/scripts/install_protobuf.sh @@ -0,0 +1,59 @@ +#!/bin/bash +set -e -x + +INSTALL_PREFIX='/usr' +DEP_FILE_PATH='/tmp/scripts/deps.txt' +while getopts "p:d:" parameter_Option +do case "${parameter_Option}" +in +p) INSTALL_PREFIX=${OPTARG};; +d) DEP_FILE_PATH=${OPTARG};; +esac +done + +EXTRA_CMAKE_ARGS="" + +case "$(uname -s)" in + Darwin*) + echo 'Building ONNX Runtime on Mac OS X' + EXTRA_CMAKE_ARGS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" + ;; + Linux*) + # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. + GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) + #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. + if [ "$GCC_VERSION" -ge 8 ]; then + CFLAGS="$CFLAGS -fstack-clash-protection" + CXXFLAGS="$CXXFLAGS -fstack-clash-protection" + fi + ARCH=$(uname -m) + + if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then + CFLAGS="$CFLAGS -fcf-protection" + CXXFLAGS="$CXXFLAGS -fcf-protection" + fi + export CFLAGS + export CXXFLAGS + ;; + *) + exit 1 +esac +mkdir -p $INSTALL_PREFIX +echo "Installing protobuf ..." +protobuf_url=$(grep '^protobuf' $DEP_FILE_PATH | cut -d ';' -f 2 ) +if [[ "$protobuf_url" = https* ]]; then + protobuf_url=$(echo $protobuf_url | sed 's/\.zip$/\.tar.gz/') + curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz $protobuf_url + mkdir protobuf + cd protobuf + tar -zxf ../protobuf_src.tar.gz --strip=1 +else + cp $protobuf_url protobuf_src.zip + unzip protobuf_src.zip + cd protobuf-* +fi + +cmake . -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF $EXTRA_CMAKE_ARGS +make -j$(getconf _NPROCESSORS_ONLN) +make install +cd .. \ No newline at end of file diff --git a/tools/ci_build/github/templates/component-governance-component-detection-steps.yml b/tools/ci_build/github/templates/component-governance-component-detection-steps.yml new file mode 100644 index 0000000..daea499 --- /dev/null +++ b/tools/ci_build/github/templates/component-governance-component-detection-steps.yml @@ -0,0 +1,18 @@ +# 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())) + inputs: + # ignore dmlc-core tracker for its CI, which is not used in onnxruntime build + # ignore unit tests in emscripten. emscripten unit tests are not used in onnxruntime build + ignoreDirectories: '$(Build.SourcesDirectory)/cmake/external/emsdk/upstream/emscripten/tests' diff --git a/tools/ci_build/github/templates/install-appcenter.yml b/tools/ci_build/github/templates/install-appcenter.yml new file mode 100644 index 0000000..51be73d --- /dev/null +++ b/tools/ci_build/github/templates/install-appcenter.yml @@ -0,0 +1,12 @@ +# Install appcenter CLI + +parameters: +- name: appcenterVersion + type: string + default: "2.13.7" + +steps: +- bash: | + set -e -x + npm install -g appcenter-cli@${{ parameters.appcenterVersion }} + displayName: Install appcenter CLI ${{ parameters.appcenterVersion }} diff --git a/tools/ci_build/github/templates/use-xcode-version.yml b/tools/ci_build/github/templates/use-xcode-version.yml new file mode 100644 index 0000000..c267ecd --- /dev/null +++ b/tools/ci_build/github/templates/use-xcode-version.yml @@ -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 }} \ No newline at end of file diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..71bd5d9 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.16.0 \ No newline at end of file From d5d617989092b88d9599463b43f88e2e0f03097e Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 14:43:33 -0700 Subject: [PATCH 06/70] add requirements.txt --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 6 +++--- tools/ci_build/github/requirements.txt | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 tools/ci_build/github/requirements.txt diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index c020be5..3186278 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -11,8 +11,8 @@ parameters: name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format jobs: -- job: IosPackaging - displayName: "iOS Packaging" +- job: SPM-IosPackaging + displayName: "SPM iOS Packaging" pool: vmImage: "macOS-13" @@ -50,7 +50,7 @@ jobs: # - template: templates/install-appcenter.yml - script: | - pip install -r tools/ci_build/github/apple/ios_packaging.requirements.txt + pip install -r tools/ci_build/github/requirements.txt displayName: "Install Python requirements" - bash: | diff --git a/tools/ci_build/github/requirements.txt b/tools/ci_build/github/requirements.txt new file mode 100644 index 0000000..adf11d6 --- /dev/null +++ b/tools/ci_build/github/requirements.txt @@ -0,0 +1 @@ +flatbuffers From b5dbb0e3419c94ff4a6436047b775cbec34cec17 Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 14:44:30 -0700 Subject: [PATCH 07/70] fix job name --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 3186278..497a245 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -11,7 +11,7 @@ parameters: name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format jobs: -- job: SPM-IosPackaging +- job: SPMIosPackaging displayName: "SPM iOS Packaging" pool: From b94ebdb145acd1d0621e1d71ba034cb8c2a2260d Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 14:48:08 -0700 Subject: [PATCH 08/70] update --- tools/ci_build/github/scripts/install_protobuf.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/ci_build/github/scripts/install_protobuf.sh b/tools/ci_build/github/scripts/install_protobuf.sh index b912b8e..3d5c3de 100644 --- a/tools/ci_build/github/scripts/install_protobuf.sh +++ b/tools/ci_build/github/scripts/install_protobuf.sh @@ -1,4 +1,3 @@ -#!/bin/bash set -e -x INSTALL_PREFIX='/usr' From cdc217733a0be37e6718dee7bbe64e018a3eff48 Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 14:50:24 -0700 Subject: [PATCH 09/70] revert --- tools/ci_build/github/scripts/install_protobuf.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_build/github/scripts/install_protobuf.sh b/tools/ci_build/github/scripts/install_protobuf.sh index 3d5c3de..b912b8e 100644 --- a/tools/ci_build/github/scripts/install_protobuf.sh +++ b/tools/ci_build/github/scripts/install_protobuf.sh @@ -1,3 +1,4 @@ +#!/bin/bash set -e -x INSTALL_PREFIX='/usr' From c7f3e089a1652c4734ade007eb889480c6c7efaf Mon Sep 17 00:00:00 2001 From: rachguo Date: Tue, 11 Jul 2023 16:45:02 -0700 Subject: [PATCH 10/70] pull more scripts and update readme --- .gitignore | 3 + README.md | 11 +- ...ult_full_ios_framework_build_settings.json | 22 ++ .../mac-ios-swift-packaging-pipeline.yml | 28 +-- .../github/scripts/assemble_c_pod_package.py | 155 +++++++++++++ .../scripts/assemble_objc_pod_package.py | 212 ++++++++++++++++++ .../scripts/build_and_assemble_ios_pods.py | 185 +++++++++++++++ .../github/scripts/package_assembly_utils.py | 130 +++++++++++ .../github/scripts/test_ios_packages.py | 192 ++++++++++++++++ 9 files changed, 916 insertions(+), 22 deletions(-) create mode 100644 tools/ci_build/github/default_full_ios_framework_build_settings.json create mode 100644 tools/ci_build/github/scripts/assemble_c_pod_package.py create mode 100755 tools/ci_build/github/scripts/assemble_objc_pod_package.py create mode 100644 tools/ci_build/github/scripts/build_and_assemble_ios_pods.py create mode 100644 tools/ci_build/github/scripts/package_assembly_utils.py create mode 100644 tools/ci_build/github/scripts/test_ios_packages.py diff --git a/.gitignore b/.gitignore index 8a30d25..2d7278a 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,6 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml + +.DS_Store +*.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 5cd7cec..24d1a87 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,9 @@ -# Project +# ONNXRuntime Swift Package Manager -> 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 [ONNXRuntime](https://github.com/microsoft/onnxruntime) repository for hosting [Swift Package Manager(SPM)](https://www.swift.org/package-manager/) support. -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. ## Contributing diff --git a/tools/ci_build/github/default_full_ios_framework_build_settings.json b/tools/ci_build/github/default_full_ios_framework_build_settings.json new file mode 100644 index 0000000..fd07074 --- /dev/null +++ b/tools/ci_build/github/default_full_ios_framework_build_settings.json @@ -0,0 +1,22 @@ +{ + "build_osx_archs": { + "iphoneos": [ + "arm64" + ], + "iphonesimulator": [ + "arm64", + "x86_64" + ] + }, + "build_params": [ + "--ios", + "--parallel", + "--use_xcode", + "--build_apple_framework", + "--use_coreml", + "--skip_tests", + "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", + "--apple_deploy_target=12.0", + "--use_xnnpack" + ] +} diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 497a245..9921349 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -47,7 +47,7 @@ jobs: parameters: xcodeVersion: ${{ variables.xcodeVersion }} - # - template: templates/install-appcenter.yml + - template: templates/install-appcenter.yml - script: | pip install -r tools/ci_build/github/requirements.txt @@ -89,18 +89,18 @@ jobs: # create and test full pods - script: | - python tools/ci_build/github/apple/build_and_assemble_ios_pods.py \ + python tools/ci_build/github/scripts/build_and_assemble_ios_pods.py \ --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ --staging-dir "$(Build.BinariesDirectory)/staging" \ --pod-version "${ORT_POD_VERSION}" \ --test \ --variant Full \ - --build-settings-file tools/ci_build/github/apple/default_full_ios_framework_build_settings.json \ + --build-settings-file tools/ci_build/github/default_full_ios_framework_build_settings.json \ -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" displayName: "[Full] Build iOS framework and assemble pod package files" - script: | - python tools/ci_build/github/apple/test_ios_packages.py \ + python tools/ci_build/github/scripts/test_ios_packages.py \ --fail_if_cocoapods_missing \ --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ @@ -123,16 +123,16 @@ jobs: workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ displayName: '[Full] Build iphone arm64 tests' - # - script: | - # set -e -x - # appcenter test run xcuitest \ - # --app "AI-Frameworks/ORT-Mobile-iOS" \ - # --devices $(app_center_test_devices) \ - # --test-series "master" \ - # --locale "en_US" \ - # --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ - # --token $(app_center_api_token) - # displayName: "[Full] Run E2E tests on App Center" + - script: | + set -e -x + appcenter test run xcuitest \ + --app "AI-Frameworks/ORT-Mobile-iOS" \ + --devices $(app_center_test_devices) \ + --test-series "master" \ + --locale "en_US" \ + --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ + --token $(app_center_api_token) + displayName: "[Full] Run E2E tests on App Center" - task: AzureCLI@2 inputs: diff --git a/tools/ci_build/github/scripts/assemble_c_pod_package.py b/tools/ci_build/github/scripts/assemble_c_pod_package.py new file mode 100644 index 0000000..14e7729 --- /dev/null +++ b/tools/ci_build/github/scripts/assemble_c_pod_package.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 + +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import pathlib +import shutil +import sys + +_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) +sys.path.append(str(_script_dir.parent)) + + +from package_assembly_utils import ( # noqa: E402 + PackageVariant, + copy_repo_relative_to_dir, + gen_file_from_template, + load_json_config, +) + + +def get_pod_config_file(package_variant: PackageVariant): + """ + Gets the pod configuration file path for the given package variant. + """ + if package_variant == PackageVariant.Full: + return _script_dir / "onnxruntime-c.config.json" + elif package_variant == PackageVariant.Mobile: + return _script_dir / "onnxruntime-mobile-c.config.json" + elif package_variant == PackageVariant.Test: + return _script_dir / "onnxruntime-test-c.config.json" + elif package_variant == PackageVariant.Training: + return _script_dir / "onnxruntime-training-c.config.json" + else: + raise ValueError(f"Unhandled package variant: {package_variant}") + + +def assemble_c_pod_package( + staging_dir: pathlib.Path, + pod_version: str, + framework_info_file: pathlib.Path, + public_headers_dir: pathlib.Path, + framework_dir: pathlib.Path, + package_variant: PackageVariant, +): + """ + Assembles the files for the C/C++ pod package in a staging directory. + + :param staging_dir Path to the staging directory for the C/C++ pod files. + :param pod_version C/C++ pod version. + :param framework_info_file Path to the framework_info.json file containing additional values for the podspec. + :param public_headers_dir Path to the public headers directory to include in the pod. + :param framework_dir Path to the onnxruntime framework directory to include in the pod. + :param package_variant The pod package variant. + :return Tuple of (package name, path to the podspec file). + """ + staging_dir = staging_dir.resolve() + framework_info_file = framework_info_file.resolve(strict=True) + public_headers_dir = public_headers_dir.resolve(strict=True) + framework_dir = framework_dir.resolve(strict=True) + + framework_info = load_json_config(framework_info_file) + pod_config = load_json_config(get_pod_config_file(package_variant)) + + pod_name = pod_config["name"] + + print(f"Assembling files in staging directory: {staging_dir}") + if staging_dir.exists(): + print("Warning: staging directory already exists", file=sys.stderr) + + # copy the necessary files to the staging directory + shutil.copytree(framework_dir, staging_dir / framework_dir.name, dirs_exist_ok=True) + shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True) + copy_repo_relative_to_dir(["LICENSE"], staging_dir) + + # generate the podspec file from the template + variable_substitutions = { + "DESCRIPTION": pod_config["description"], + "IOS_DEPLOYMENT_TARGET": framework_info["IOS_DEPLOYMENT_TARGET"], + "LICENSE_FILE": "LICENSE", + "NAME": pod_name, + "ORT_C_FRAMEWORK": framework_dir.name, + "ORT_C_HEADERS_DIR": public_headers_dir.name, + "SUMMARY": pod_config["summary"], + "VERSION": pod_version, + "WEAK_FRAMEWORK": framework_info["WEAK_FRAMEWORK"], + } + + podspec_template = _script_dir / "c.podspec.template" + podspec = staging_dir / f"{pod_name}.podspec" + + gen_file_from_template(podspec_template, podspec, variable_substitutions) + + return pod_name, podspec + + +def parse_args(): + parser = argparse.ArgumentParser( + description=""" + Assembles the files for the C/C++ pod package in a staging directory. + This directory can be validated (e.g., with `pod lib lint`) and then zipped to create a package for release. + """ + ) + + parser.add_argument( + "--staging-dir", + type=pathlib.Path, + default=pathlib.Path("./c-staging"), + help="Path to the staging directory for the C/C++ pod files.", + ) + parser.add_argument("--pod-version", required=True, help="C/C++ pod version.") + parser.add_argument( + "--framework-info-file", + type=pathlib.Path, + required=True, + help="Path to the framework_info.json file containing additional values for the podspec. " + "This file should be generated by CMake in the build directory.", + ) + parser.add_argument( + "--public-headers-dir", + type=pathlib.Path, + required=True, + help="Path to the public headers directory to include in the pod.", + ) + parser.add_argument( + "--framework-dir", + type=pathlib.Path, + required=True, + help="Path to the onnxruntime framework directory to include in the pod.", + ) + parser.add_argument( + "--variant", choices=PackageVariant.all_variant_names(), required=True, help="Pod package variant." + ) + + return parser.parse_args() + + +def main(): + args = parse_args() + + assemble_c_pod_package( + staging_dir=args.staging_dir, + pod_version=args.pod_version, + framework_info_file=args.framework_info_file, + public_headers_dir=args.public_headers_dir, + framework_dir=args.framework_dir, + package_variant=PackageVariant[args.variant], + ) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/ci_build/github/scripts/assemble_objc_pod_package.py b/tools/ci_build/github/scripts/assemble_objc_pod_package.py new file mode 100755 index 0000000..709c7ea --- /dev/null +++ b/tools/ci_build/github/scripts/assemble_objc_pod_package.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python3 + +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import pathlib +import sys + +_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) +sys.path.append(str(_script_dir.parent)) + + +from assemble_c_pod_package import get_pod_config_file as get_c_pod_config_file # noqa: E402 +from package_assembly_utils import ( # noqa: E402 + PackageVariant, + copy_repo_relative_to_dir, + filter_files, + gen_file_from_template, + load_json_config, +) + +# these variables contain paths or path patterns that are relative to the repo root + +# the license file +license_file = "LICENSE" + +# include directories for compiling the pod itself +include_dirs = [ + "objectivec", +] + +all_objc_files = { + "source_files": [ + "objectivec/include/*.h", + "objectivec/*.h", + "objectivec/*.m", + "objectivec/*.mm", + ], + "public_header_files": [ + "objectivec/include/*.h", + ], + "test_source_files": [ + "objectivec/test/*.h", + "objectivec/test/*.m", + "objectivec/test/*.mm", + ], + "test_resource_files": [ + "objectivec/test/testdata/*.ort", + "onnxruntime/test/testdata/training_api/*", + ], +} + +training_only_objc_files = { + "source_files": [ + "objectivec/include/onnxruntime_training.h", + "objectivec/include/ort_checkpoint.h", + "objectivec/include/ort_training_session.h", + "objectivec/ort_checkpoint.mm", + "objectivec/ort_checkpoint_internal.h", + "objectivec/ort_training_session_internal.h", + "objectivec/ort_training_session.mm", + ], + "public_header_files": [ + "objectivec/include/ort_checkpoint.h", + "objectivec/include/ort_training_session.h", + "objectivec/include/onnxruntime_training.h", + ], + "test_source_files": [ + "objectivec/test/ort_training_session_test.mm", + "objectivec/test/ort_checkpoint_test.mm", + "objectivec/test/ort_training_utils_test.mm", + ], + "test_resource_files": [ + "onnxruntime/test/testdata/training_api/*", + ], +} + + +def get_pod_files(package_variant: PackageVariant): + """ + Gets the source and header files for the given package variant. + """ + if package_variant == PackageVariant.Training: + return all_objc_files + else: + # return files that are in pod_files but not in training_only_objc_files + filtered_pod_files = {} + for key in all_objc_files: + filtered_pod_files[key] = filter_files(all_objc_files[key], training_only_objc_files[key]) + return filtered_pod_files + + +def get_pod_config_file(package_variant: PackageVariant): + """ + Gets the pod configuration file path for the given package variant. + """ + if package_variant == PackageVariant.Full: + return _script_dir / "onnxruntime-objc.config.json" + elif package_variant == PackageVariant.Mobile: + return _script_dir / "onnxruntime-mobile-objc.config.json" + elif package_variant == PackageVariant.Training: + return _script_dir / "onnxruntime-training-objc.config.json" + else: + raise ValueError(f"Unhandled package variant: {package_variant}") + + +def assemble_objc_pod_package( + staging_dir: pathlib.Path, pod_version: str, framework_info_file: pathlib.Path, package_variant: PackageVariant +): + """ + Assembles the files for the Objective-C pod package in a staging directory. + + :param staging_dir Path to the staging directory for the Objective-C pod files. + :param pod_version Objective-C pod version. + :param framework_info_file Path to the framework_info.json file containing additional values for the podspec. + :param package_variant The pod package variant. + :return Tuple of (package name, path to the podspec file). + """ + staging_dir = staging_dir.resolve() + framework_info_file = framework_info_file.resolve(strict=True) + + framework_info = load_json_config(framework_info_file) + pod_config = load_json_config(get_pod_config_file(package_variant)) + c_pod_config = load_json_config(get_c_pod_config_file(package_variant)) + + pod_name = pod_config["name"] + + print(f"Assembling files in staging directory: {staging_dir}") + if staging_dir.exists(): + print("Warning: staging directory already exists", file=sys.stderr) + + pod_files = get_pod_files(package_variant) + + # copy the necessary files to the staging directory + copy_repo_relative_to_dir( + [license_file, *pod_files["source_files"], *pod_files["test_source_files"], *pod_files["test_resource_files"]], + staging_dir, + ) + + # generate the podspec file from the template + + def path_patterns_as_variable_value(patterns: list[str]): + return ", ".join([f'"{pattern}"' for pattern in patterns]) + + variable_substitutions = { + "C_POD_NAME": c_pod_config["name"], + "DESCRIPTION": pod_config["description"], + "INCLUDE_DIR_LIST": path_patterns_as_variable_value(include_dirs), + "IOS_DEPLOYMENT_TARGET": framework_info["IOS_DEPLOYMENT_TARGET"], + "LICENSE_FILE": license_file, + "NAME": pod_name, + "PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(pod_files["public_header_files"]), + "SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["source_files"]), + "SUMMARY": pod_config["summary"], + "TEST_RESOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_resource_files"]), + "TEST_SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_source_files"]), + "VERSION": pod_version, + } + + podspec_template = _script_dir / "objc.podspec.template" + podspec = staging_dir / f"{pod_name}.podspec" + + gen_file_from_template(podspec_template, podspec, variable_substitutions) + + return pod_name, podspec + + +def parse_args(): + parser = argparse.ArgumentParser( + description=""" + Assembles the files for the Objective-C pod package in a staging directory. + This directory can be validated (e.g., with `pod lib lint`) and then zipped to create a package for release. + """ + ) + + parser.add_argument( + "--staging-dir", + type=pathlib.Path, + default=pathlib.Path("./onnxruntime-mobile-objc-staging"), + help="Path to the staging directory for the Objective-C pod files.", + ) + parser.add_argument("--pod-version", required=True, help="Objective-C pod version.") + parser.add_argument( + "--framework-info-file", + type=pathlib.Path, + required=True, + help="Path to the framework_info.json file containing additional values for the podspec. " + "This file should be generated by CMake in the build directory.", + ) + parser.add_argument( + "--variant", choices=PackageVariant.release_variant_names(), required=True, help="Pod package variant." + ) + + return parser.parse_args() + + +def main(): + args = parse_args() + + assemble_objc_pod_package( + staging_dir=args.staging_dir, + pod_version=args.pod_version, + framework_info_file=args.framework_info_file, + package_variant=PackageVariant[args.variant], + ) + + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py b/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py new file mode 100644 index 0000000..9713283 --- /dev/null +++ b/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python3 + +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import logging +import pathlib +import shutil +import sys +import tempfile + +from assemble_c_pod_package import assemble_c_pod_package +from assemble_objc_pod_package import assemble_objc_pod_package +from package_assembly_utils import PackageVariant, get_ort_version + +SCRIPT_PATH = pathlib.Path(__file__).resolve() +SCRIPT_DIR = SCRIPT_PATH.parent +REPO_DIR = SCRIPT_PATH.parents[4] + + +logging.basicConfig(format="%(asctime)s %(name)s [%(levelname)s] - %(message)s", level=logging.DEBUG) +log = logging.getLogger(SCRIPT_PATH.stem) + + +def parse_args(): + parser = argparse.ArgumentParser( + description="Builds an iOS framework and uses it to assemble iOS pod package files.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument( + "--build-dir", + type=pathlib.Path, + default=REPO_DIR / "build" / "ios_framework", + help="The build directory. This will contain the iOS framework build output.", + ) + parser.add_argument( + "--staging-dir", + type=pathlib.Path, + default=REPO_DIR / "build" / "ios_pod_staging", + help="The staging directory. This will contain the iOS pod package files. " + "The pod package files do not have dependencies on files in the build directory.", + ) + + parser.add_argument( + "--pod-version", + default=f"{get_ort_version()}-local", + help="The version string of the pod. The same version is used for all pods.", + ) + + parser.add_argument( + "--variant", + choices=PackageVariant.release_variant_names(), + default=PackageVariant.Mobile.name, + help="Pod package variant.", + ) + + parser.add_argument("--test", action="store_true", help="Run tests on the framework and pod package files.") + + build_framework_group = parser.add_argument_group( + title="iOS framework build arguments", + description="See the corresponding arguments in build_ios_framework.py for details.", + ) + + build_framework_group.add_argument("--include-ops-by-config") + build_framework_group.add_argument( + "--build-settings-file", required=True, help="The positional argument of build_ios_framework.py." + ) + build_framework_group.add_argument( + "-b", + "--build-ios-framework-arg", + action="append", + dest="build_ios_framework_extra_args", + default=[], + help="Pass an argument through to build_ios_framework.py. This may be specified multiple times.", + ) + + args = parser.parse_args() + + return args + + +def run(arg_list, cwd=None): + import os + import shlex + import subprocess + + log.info( + "Running subprocess in '{}'\n {}".format(cwd or os.getcwd(), " ".join([shlex.quote(arg) for arg in arg_list])) + ) + + return subprocess.run(arg_list, check=True, cwd=cwd) + + +def main(): + args = parse_args() + + build_dir = args.build_dir.resolve() + staging_dir = args.staging_dir.resolve() + + # build framework + package_variant = PackageVariant[args.variant] + framework_info_file = build_dir / "framework_info.json" + + log.info("Building iOS framework.") + + build_ios_framework_args = [ + sys.executable, + str(SCRIPT_DIR / "build_ios_framework.py"), + *args.build_ios_framework_extra_args, + ] + + if args.include_ops_by_config is not None: + build_ios_framework_args += ["--include_ops_by_config", args.include_ops_by_config] + + build_ios_framework_args += ["--build_dir", str(build_dir), args.build_settings_file] + + run(build_ios_framework_args) + + if args.test: + test_ios_packages_args = [ + sys.executable, + str(SCRIPT_DIR / "test_ios_packages.py"), + "--fail_if_cocoapods_missing", + "--framework_info_file", + str(framework_info_file), + "--c_framework_dir", + str(build_dir / "framework_out"), + "--variant", + package_variant.name, + ] + + run(test_ios_packages_args) + + # assemble pods and then move them to their target locations (staging_dir/) + staging_dir.mkdir(parents=True, exist_ok=True) + with tempfile.TemporaryDirectory(dir=staging_dir) as pod_assembly_dir_name: + pod_assembly_dir = pathlib.Path(pod_assembly_dir_name) + + log.info("Assembling C/C++ pod.") + + c_pod_staging_dir = pod_assembly_dir / "c_pod" + c_pod_name, c_pod_podspec = assemble_c_pod_package( + staging_dir=c_pod_staging_dir, + pod_version=args.pod_version, + framework_info_file=framework_info_file, + framework_dir=build_dir / "framework_out" / "onnxruntime.xcframework", + public_headers_dir=build_dir / "framework_out" / "Headers", + package_variant=package_variant, + ) + + if args.test: + test_c_pod_args = ["pod", "lib", "lint", "--verbose"] + + run(test_c_pod_args, cwd=c_pod_staging_dir) + + log.info("Assembling Objective-C pod.") + + objc_pod_staging_dir = pod_assembly_dir / "objc_pod" + objc_pod_name, objc_pod_podspec = assemble_objc_pod_package( + staging_dir=objc_pod_staging_dir, + pod_version=args.pod_version, + framework_info_file=framework_info_file, + package_variant=package_variant, + ) + + if args.test: + test_objc_pod_args = ["pod", "lib", "lint", "--verbose", f"--include-podspecs={c_pod_podspec}"] + + run(test_objc_pod_args, cwd=objc_pod_staging_dir) + + def move_dir(src, dst): + if dst.is_dir(): + shutil.rmtree(dst) + shutil.move(src, dst) + + move_dir(c_pod_staging_dir, staging_dir / c_pod_name) + move_dir(objc_pod_staging_dir, staging_dir / objc_pod_name) + + log.info(f"Successfully assembled iOS pods at '{staging_dir}'.") + + +if __name__ == "__main__": + main() diff --git a/tools/ci_build/github/scripts/package_assembly_utils.py b/tools/ci_build/github/scripts/package_assembly_utils.py new file mode 100644 index 0000000..e594077 --- /dev/null +++ b/tools/ci_build/github/scripts/package_assembly_utils.py @@ -0,0 +1,130 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import enum +import json +import os +import pathlib +import re +import shutil +from typing import Dict, List + +_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) +repo_root = _script_dir.parents[3] + + +class PackageVariant(enum.Enum): + Full = 0 # full ORT build with all opsets, ops, and types + Mobile = 1 # minimal ORT build with reduced ops + Training = 2 # full ORT build with all opsets, ops, and types, plus training APIs + Test = -1 # for testing purposes only + + @classmethod + def release_variant_names(cls): + return [v.name for v in cls if v.value >= 0] + + @classmethod + def all_variant_names(cls): + return [v.name for v in cls] + + +_template_variable_pattern = re.compile(r"@(\w+)@") # match "@var@" + + +def gen_file_from_template( + template_file: pathlib.Path, output_file: pathlib.Path, variable_substitutions: Dict[str, str], strict: bool = True +): + """ + Generates a file from a template file. + The template file may contain template variables that will be substituted + with the provided values in the generated output file. + In the template file, template variable names are delimited by "@"'s, + e.g., "@var@". + + :param template_file The template file path. + :param output_file The generated output file path. + :param variable_substitutions The mapping from template variable name to value. + :param strict Whether to require the set of template variable names in the file and the keys of + `variable_substitutions` to be equal. + """ + with open(template_file) as template: + content = template.read() + + variables_in_file = set() + + def replace_template_variable(match): + variable_name = match.group(1) + variables_in_file.add(variable_name) + return variable_substitutions.get(variable_name, match.group(0)) + + content = _template_variable_pattern.sub(replace_template_variable, content) + + if strict and variables_in_file != variable_substitutions.keys(): + variables_in_substitutions = set(variable_substitutions.keys()) + raise ValueError( + f"Template file variables and substitution variables do not match. " + f"Only in template file: {sorted(variables_in_file - variables_in_substitutions)}. " + f"Only in substitutions: {sorted(variables_in_substitutions - variables_in_file)}." + ) + + with open(output_file, mode="w") as output: + output.write(content) + + +def filter_files(all_file_patterns: List[str], excluded_file_patterns: List[str]): + """ + Filters file paths based on inclusion and exclusion patterns + + :param all_file_patterns The list of file paths to filter. + :param excluded_file_patterns The list of exclusion patterns. + + :return The filtered list of file paths + """ + # get all files matching the patterns in all_file_patterns + all_files = [str(path.relative_to(repo_root)) for pattern in all_file_patterns for path in repo_root.glob(pattern)] + + # get all files matching the patterns in excluded_file_patterns + exclude_files = [ + str(path.relative_to(repo_root)) for pattern in excluded_file_patterns for path in repo_root.glob(pattern) + ] + + # return the difference + return list(set(all_files) - set(exclude_files)) + + +def copy_repo_relative_to_dir(patterns: List[str], dest_dir: pathlib.Path): + """ + Copies file paths relative to the repo root to a directory. + The given paths or path patterns are relative to the repo root, and the + repo root-relative intermediate directory structure is maintained. + + :param patterns The paths or path patterns relative to the repo root. + :param dest_dir The destination directory. + """ + paths = [path for pattern in patterns for path in repo_root.glob(pattern)] + for path in paths: + repo_relative_path = path.relative_to(repo_root) + dst_path = dest_dir / repo_relative_path + os.makedirs(dst_path.parent, exist_ok=True) + shutil.copy(path, dst_path) + + +def load_json_config(json_config_file: pathlib.Path): + """ + Loads configuration info from a JSON file. + + :param json_config_file The JSON configuration file path. + :return The configuration info values. + """ + with open(json_config_file) as config: + return json.load(config) + + +def get_ort_version(): + """ + Gets the ONNX Runtime version string from the repo. + + :return The ONNX Runtime version string. + """ + with open(repo_root / "VERSION_NUMBER") as version_file: + return version_file.read().strip() diff --git a/tools/ci_build/github/scripts/test_ios_packages.py b/tools/ci_build/github/scripts/test_ios_packages.py new file mode 100644 index 0000000..e53a884 --- /dev/null +++ b/tools/ci_build/github/scripts/test_ios_packages.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import argparse +import contextlib +import os +import pathlib +import shutil +import subprocess +import tempfile + +from assemble_c_pod_package import assemble_c_pod_package +from package_assembly_utils import PackageVariant, gen_file_from_template, get_ort_version + +SCRIPT_PATH = pathlib.Path(__file__).resolve(strict=True) +REPO_DIR = SCRIPT_PATH.parents[4] + + +def _test_ios_packages(args): + # check if CocoaPods is installed + if shutil.which("pod") is None: + if args.fail_if_cocoapods_missing: + raise ValueError("CocoaPods is required for this test") + else: + print("CocoaPods is not installed, ignore this test") + return + + # Now we need to create a zip file contains the framework and the podspec file, both of these 2 files + # should be under the c_framework_dir + c_framework_dir = args.c_framework_dir.resolve() + if not c_framework_dir.is_dir(): + raise FileNotFoundError(f"c_framework_dir {c_framework_dir} is not a folder.") + + has_framework = (c_framework_dir / "onnxruntime.framework").exists() + has_xcframework = (c_framework_dir / "onnxruntime.xcframework").exists() + + if not has_framework and not has_xcframework: + raise FileNotFoundError(f"{c_framework_dir} does not have onnxruntime.framework/xcframework") + + if has_framework and has_xcframework: + raise ValueError("Cannot proceed when both onnxruntime.framework and onnxruntime.xcframework exist") + + framework_name = "onnxruntime.framework" if has_framework else "onnxruntime.xcframework" + + # create a temp folder + + with contextlib.ExitStack() as context_stack: + if args.test_project_stage_dir is None: + stage_dir = pathlib.Path(context_stack.enter_context(tempfile.TemporaryDirectory())).resolve() + else: + # If we specify the stage dir, then use it to create test project + stage_dir = args.test_project_stage_dir.resolve() + if os.path.exists(stage_dir): + shutil.rmtree(stage_dir) + os.makedirs(stage_dir) + + # assemble the test project here + target_proj_path = stage_dir / "ios_package_test" + + # copy the test project source files to target_proj_path + test_proj_path = pathlib.Path(REPO_DIR, "onnxruntime/test/platform/ios/ios_package_test") + shutil.copytree(test_proj_path, target_proj_path) + + # assemble local pod files here + local_pods_dir = stage_dir / "local_pods" + + # We will only publish xcframework, however, assembly of the xcframework is a post process + # and it cannot be done by CMake for now. See, https://gitlab.kitware.com/cmake/cmake/-/issues/21752 + # For a single sysroot and arch built by build.py or cmake, we can only generate framework + # We still need a way to test it. framework_dir and public_headers_dir have different values when testing a + # framework and a xcframework. + framework_dir = args.c_framework_dir / framework_name + public_headers_dir = framework_dir / "Headers" if has_framework else args.c_framework_dir / "Headers" + + pod_name, podspec = assemble_c_pod_package( + staging_dir=local_pods_dir, + pod_version=get_ort_version(), + framework_info_file=args.framework_info_file, + public_headers_dir=public_headers_dir, + framework_dir=framework_dir, + package_variant=PackageVariant[args.variant], + ) + + # move podspec out to target_proj_path first + podspec = shutil.move(podspec, target_proj_path / podspec.name) + + # create a zip file contains the framework + zip_file_path = local_pods_dir / f"{pod_name}.zip" + # shutil.make_archive require target file as full path without extension + shutil.make_archive(zip_file_path.with_suffix(""), "zip", root_dir=local_pods_dir) + + # update the podspec to point to the local framework zip file + with open(podspec) as file: + file_data = file.read() + + file_data = file_data.replace("file:///http_source_placeholder", f"file:///{zip_file_path}") + + with open(podspec, "w") as file: + file.write(file_data) + + # generate Podfile to point to pod + gen_file_from_template( + target_proj_path / "Podfile.template", + target_proj_path / "Podfile", + {"C_POD_NAME": pod_name, "C_POD_PODSPEC": f"./{podspec.name}"}, + ) + + # clean the Cocoapods cache first, in case the same pod was cached in previous runs + subprocess.run(["pod", "cache", "clean", "--all"], shell=False, check=True, cwd=target_proj_path) + + # install pods + subprocess.run(["pod", "install"], shell=False, check=True, cwd=target_proj_path) + + # run the tests + if not args.prepare_test_project_only: + simulator_device_name = subprocess.check_output( + ["bash", str(REPO_DIR / "tools" / "ci_build" / "github" / "apple" / "get_simulator_device_name.sh")], + text=True, + ).strip() + + subprocess.run( + [ + "xcrun", + "xcodebuild", + "test", + "-workspace", + "./ios_package_test.xcworkspace", + "-scheme", + "ios_package_test", + "-destination", + f"platform=iOS Simulator,OS=latest,name={simulator_device_name}", + ], + shell=False, + check=True, + cwd=target_proj_path, + ) + + +def parse_args(): + parser = argparse.ArgumentParser( + os.path.basename(__file__), description="Test iOS framework using CocoaPods package." + ) + + parser.add_argument( + "--fail_if_cocoapods_missing", + action="store_true", + help="This script will fail if CocoaPods is not installed, " + "will not throw error unless fail_if_cocoapod_missing is set.", + ) + + parser.add_argument( + "--framework_info_file", + type=pathlib.Path, + required=True, + help="Path to the framework_info.json file containing additional values for the podspec. " + "This file should be generated by CMake in the build directory.", + ) + + parser.add_argument( + "--c_framework_dir", type=pathlib.Path, required=True, help="Provide the parent directory for C/C++ framework" + ) + + parser.add_argument( + "--variant", + choices=PackageVariant.all_variant_names(), + default=PackageVariant.Test.name, + help="Pod package variant.", + ) + + parser.add_argument( + "--test_project_stage_dir", + type=pathlib.Path, + help="The stage dir for the test project, if not specified, will use a temporary path", + ) + + parser.add_argument( + "--prepare_test_project_only", + action="store_true", + help="Prepare the test project only, without running the tests", + ) + + return parser.parse_args() + + +def main(): + args = parse_args() + _test_ios_packages(args) + + +if __name__ == "__main__": + main() From 0660d2b9a7116a882352d8f2fa899e11fca52fe9 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 13:50:14 -0700 Subject: [PATCH 11/70] try downloading from ios packaging pipeline --- .../mac-ios-swift-packaging-pipeline.yml | 150 +++++++++--------- 1 file changed, 79 insertions(+), 71 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 9921349..a04a341 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -83,69 +83,77 @@ jobs: set_var "ORT_SHOULD_UPLOAD_ARCHIVES" "${SHOULD_UPLOAD_ARCHIVES}" displayName: "Set variables" - - script: | - $(Build.SourcesDirectory)/tools/ci_build/github/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt - displayName: "Build Host Protoc" + # - script: | + # $(Build.SourcesDirectory)/tools/ci_build/github/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt + # displayName: "Build Host Protoc" - # create and test full pods - - script: | - python tools/ci_build/github/scripts/build_and_assemble_ios_pods.py \ - --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ - --staging-dir "$(Build.BinariesDirectory)/staging" \ - --pod-version "${ORT_POD_VERSION}" \ - --test \ - --variant Full \ - --build-settings-file tools/ci_build/github/default_full_ios_framework_build_settings.json \ - -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" - displayName: "[Full] Build iOS framework and assemble pod package files" + # # create and test full pods + # - script: | + # python tools/ci_build/github/scripts/build_and_assemble_ios_pods.py \ + # --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ + # --staging-dir "$(Build.BinariesDirectory)/staging" \ + # --pod-version "${ORT_POD_VERSION}" \ + # --test \ + # --variant Full \ + # --build-settings-file tools/ci_build/github/default_full_ios_framework_build_settings.json \ + # -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" + # displayName: "[Full] Build iOS framework and assemble pod package files" - - script: | - python tools/ci_build/github/scripts/test_ios_packages.py \ - --fail_if_cocoapods_missing \ - --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ - --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ - --variant Full \ - --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_full" \ - --prepare_test_project_only - displayName: "[Full] Assemble test project for App Center" + # - script: | + # python tools/ci_build/github/scripts/test_ios_packages.py \ + # --fail_if_cocoapods_missing \ + # --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ + # --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ + # --variant Full \ + # --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_full" \ + # --prepare_test_project_only + # displayName: "[Full] Assemble test project for App Center" - - task: Xcode@5 - inputs: - actions: 'build-for-testing' - configuration: 'Debug' - xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ios_package_test.xcworkspace' - sdk: 'iphoneos' - scheme: 'ios_package_test' - signingOption: 'manual' - signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' - provisioningProfileName: 'iOS Team Provisioning Profile' - args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData' - workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ - displayName: '[Full] Build iphone arm64 tests' + # - task: Xcode@5 + # inputs: + # actions: 'build-for-testing' + # configuration: 'Debug' + # xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ios_package_test.xcworkspace' + # sdk: 'iphoneos' + # scheme: 'ios_package_test' + # signingOption: 'manual' + # signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' + # provisioningProfileName: 'iOS Team Provisioning Profile' + # args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData' + # workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ + # displayName: '[Full] Build iphone arm64 tests' - - script: | - set -e -x - appcenter test run xcuitest \ - --app "AI-Frameworks/ORT-Mobile-iOS" \ - --devices $(app_center_test_devices) \ - --test-series "master" \ - --locale "en_US" \ - --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ - --token $(app_center_api_token) - displayName: "[Full] Run E2E tests on App Center" + # - script: | + # set -e -x + # appcenter test run xcuitest \ + # --app "AI-Frameworks/ORT-Mobile-iOS" \ + # --devices $(app_center_test_devices) \ + # --test-series "master" \ + # --locale "en_US" \ + # --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ + # --token $(app_center_api_token) + # displayName: "[Full] Run E2E tests on App Center" - - task: AzureCLI@2 - inputs: - azureSubscription: 'AIInfraBuildOnnxRuntimeOSS' - scriptType: 'bash' - scriptLocation: 'scriptPath' - scriptPath: 'tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh' - arguments: >- - "$(Build.BinariesDirectory)/staging" - "$(Build.ArtifactStagingDirectory)" - "$(ORT_POD_VERSION)" - "$(ORT_SHOULD_UPLOAD_ARCHIVES)" - displayName: "Assemble artifacts" + # - task: AzureCLI@2 + # inputs: + # azureSubscription: 'AIInfraBuildOnnxRuntimeOSS' + # scriptType: 'bash' + # scriptLocation: 'scriptPath' + # scriptPath: 'tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh' + # arguments: >- + # "$(Build.BinariesDirectory)/staging" + # "$(Build.ArtifactStagingDirectory)" + # "$(ORT_POD_VERSION)" + # "$(ORT_SHOULD_UPLOAD_ARCHIVES)" + # displayName: "Assemble artifacts" + + # TODO: Download artifacts from the onnxruntime-ios-packaging pipeline artifacts folder + + - task: DownloadPipelineArtifact@0 + inputs: + pipelineId: '995' #The specific pipeline to download from. + artifactName: 'ios_packaging_artifacts' # string. Required. The name of artifact to download. Default: drop. + targetPath: "$(Build.ArtifactStagingDirectory)" # string. Required. Path to download to. - script: | set -e -x @@ -161,18 +169,18 @@ jobs: # 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 - cp "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" - xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' - rm swift/pod-archive-onnxruntime-c-*.zip - displayName: "Test Package.swift usage" + # - script: | + # set -e -x + # cp "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" swift/ + # export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" + # xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' + # rm swift/pod-archive-onnxruntime-c-*.zip + # displayName: "Test Package.swift usage" - - publish: "$(Build.ArtifactStagingDirectory)" - artifact: ios_packaging_artifacts - displayName: "Publish artifacts" + # - publish: "$(Build.ArtifactStagingDirectory)" + # artifact: ios_packaging_artifacts + # displayName: "Publish artifacts" - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' + # - template: templates/component-governance-component-detection-steps.yml + # parameters : + # condition : 'succeeded' From 9a18dd9782660b5f0f6b2cead86ddd26e214890b Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 13:52:12 -0700 Subject: [PATCH 12/70] fix --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index a04a341..286da6a 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -150,10 +150,10 @@ jobs: # TODO: Download artifacts from the onnxruntime-ios-packaging pipeline artifacts folder - task: DownloadPipelineArtifact@0 - inputs: - pipelineId: '995' #The specific pipeline to download from. - artifactName: 'ios_packaging_artifacts' # string. Required. The name of artifact to download. Default: drop. - targetPath: "$(Build.ArtifactStagingDirectory)" # string. Required. Path to download to. + inputs: + pipelineId: '995' #The specific pipeline to download from. + artifactName: 'ios_packaging_artifacts' # string. Required. The name of artifact to download. Default: drop. + targetPath: "$(Build.ArtifactStagingDirectory)" # string. Required. Path to download to. - script: | set -e -x From 69fd3e033953fba3a11ebacb398d8c78629e09b2 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 14:02:10 -0700 Subject: [PATCH 13/70] try build id --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 286da6a..26cda1e 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -151,7 +151,7 @@ jobs: - task: DownloadPipelineArtifact@0 inputs: - pipelineId: '995' #The specific pipeline to download from. + pipelineId: '326908' #The specific pipeline to download from. artifactName: 'ios_packaging_artifacts' # string. Required. The name of artifact to download. Default: drop. targetPath: "$(Build.ArtifactStagingDirectory)" # string. Required. Path to download to. From 4e86c3c7fbdde1a73b39624bf84bf864bc08c02c Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 14:02:56 -0700 Subject: [PATCH 14/70] test --- .../mac-ios-swift-packaging-pipeline.yml | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 26cda1e..9000f36 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -23,19 +23,19 @@ jobs: timeoutInMinutes: 300 steps: - - task: InstallAppleCertificate@2 - inputs: - certSecureFile: '$(ios_signing_certificate_name)' - certPwd: '$(ios_signing_certificate_password)' - keychain: 'temp' - deleteCert: true - displayName: 'Install ORT Mobile Test Signing Certificate' + # - task: InstallAppleCertificate@2 + # inputs: + # certSecureFile: '$(ios_signing_certificate_name)' + # certPwd: '$(ios_signing_certificate_password)' + # keychain: 'temp' + # deleteCert: true + # displayName: 'Install ORT Mobile Test Signing Certificate' - - task: InstallAppleProvisioningProfile@1 - inputs: - provProfileSecureFile: '$(ios_provision_profile_name)' - removeProfile: true - displayName: 'Install ORT Mobile Test Provisioning Profile' + # - task: InstallAppleProvisioningProfile@1 + # inputs: + # provProfileSecureFile: '$(ios_provision_profile_name)' + # removeProfile: true + # displayName: 'Install ORT Mobile Test Provisioning Profile' - task: UsePythonVersion@0 inputs: @@ -47,7 +47,7 @@ jobs: parameters: xcodeVersion: ${{ variables.xcodeVersion }} - - template: templates/install-appcenter.yml + # - template: templates/install-appcenter.yml - script: | pip install -r tools/ci_build/github/requirements.txt From b3d6d8e3674e13c2e1fa9bf4dd57c8465644f332 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 14:25:46 -0700 Subject: [PATCH 15/70] try download artifacts task @2 --- .../github/mac-ios-swift-packaging-pipeline.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 9000f36..8845277 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -149,11 +149,13 @@ jobs: # TODO: Download artifacts from the onnxruntime-ios-packaging pipeline artifacts folder - - task: DownloadPipelineArtifact@0 + # Download artifacts from a specific pipeline. + - task: DownloadPipelineArtifact@2 inputs: - pipelineId: '326908' #The specific pipeline to download from. - artifactName: 'ios_packaging_artifacts' # string. Required. The name of artifact to download. Default: drop. - targetPath: "$(Build.ArtifactStagingDirectory)" # string. Required. Path to download to. + buildType: 'normal' + definition: 995 + buildVersionToDownload: 'latest' + targetPath: '$(Build.ArtifactStagingDirectory)' - script: | set -e -x From b91ec00488a2681d9c72a9a10e4904cdf0dcbd74 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 14:37:29 -0700 Subject: [PATCH 16/70] remove buildtype --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 8845277..13a4633 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -152,7 +152,6 @@ jobs: # Download artifacts from a specific pipeline. - task: DownloadPipelineArtifact@2 inputs: - buildType: 'normal' definition: 995 buildVersionToDownload: 'latest' targetPath: '$(Build.ArtifactStagingDirectory)' From 3067c02628778a60c5cedba11684e9aaa0d0d9aa Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 15:15:45 -0700 Subject: [PATCH 17/70] update project name --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 13a4633..f3fdb0b 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -152,6 +152,8 @@ jobs: # Download artifacts from a specific pipeline. - task: DownloadPipelineArtifact@2 inputs: + buildType: 'specific' + project: 'Lotus' definition: 995 buildVersionToDownload: 'latest' targetPath: '$(Build.ArtifactStagingDirectory)' From 4a92d42e947aecc3f4f40eeb69a6a5e4afc97997 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 16:57:06 -0700 Subject: [PATCH 18/70] try listing artifacts --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index f3fdb0b..fde6826 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -165,7 +165,9 @@ jobs: - script: | set -e -x - shasum -a 256 "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" + ARTIFACTS_LIST=${ls -R "$(Build.ArtifactStagingDirectory)"} + POD_ARCHIVE=${echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5} + shasum -a 256 "${POD_ARCHIVE}" displayName: "Print ORT iOS Pod checksum" From 17b1e36306b2c996370ba4cbbca9393dd2000fd4 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:01:47 -0700 Subject: [PATCH 19/70] syntax --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index fde6826..7035383 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -165,8 +165,8 @@ jobs: - script: | set -e -x - ARTIFACTS_LIST=${ls -R "$(Build.ArtifactStagingDirectory)"} - POD_ARCHIVE=${echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5} + ARTIFACTS_LIST=$(ls -R "$(Build.ArtifactStagingDirectory)") + POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5) shasum -a 256 "${POD_ARCHIVE}" displayName: "Print ORT iOS Pod checksum" From d52308b0db88bc9c93804dcee84a373a30c0fcd7 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:09:59 -0700 Subject: [PATCH 20/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 7035383..605ec23 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -160,14 +160,16 @@ jobs: - script: | set -e -x - ls -R "$(Build.ArtifactStagingDirectory)" + ls + workingDirectory: '$(Build.ArtifactStagingDirectory)"/ios_packaging_artifacts' displayName: "List staged artifacts" - script: | set -e -x - ARTIFACTS_LIST=$(ls -R "$(Build.ArtifactStagingDirectory)") + ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5) shasum -a 256 "${POD_ARCHIVE}" + workingDirectory: '$(Build.ArtifactStagingDirectory)"/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From 413192c425058239889cc5be2ca41f02798f9c9c Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:16:51 -0700 Subject: [PATCH 21/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 605ec23..53843ec 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -161,7 +161,7 @@ jobs: - script: | set -e -x ls - workingDirectory: '$(Build.ArtifactStagingDirectory)"/ios_packaging_artifacts' + workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "List staged artifacts" - script: | @@ -169,7 +169,7 @@ jobs: ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5) shasum -a 256 "${POD_ARCHIVE}" - workingDirectory: '$(Build.ArtifactStagingDirectory)"/ios_packaging_artifacts' + workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From 7e67e2a59ce46db3d9b754d2421f8824faad8a8d Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:23:29 -0700 Subject: [PATCH 22/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 53843ec..484d450 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -167,7 +167,7 @@ jobs: - script: | set -e -x ARTIFACTS_LIST=$(ls) - POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | cut -d$'\n' -f5) + POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') shasum -a 256 "${POD_ARCHIVE}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From b885049fedf8334927859ba7cb2878a9d1218bb2 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:45:36 -0700 Subject: [PATCH 23/70] update test package.swift --- .../github/mac-ios-swift-packaging-pipeline.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 484d450..4a55d70 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -176,13 +176,14 @@ jobs: # 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 - # cp "$(Build.ArtifactStagingDirectory)/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" swift/ - # export ORT_IOS_POD_LOCAL_PATH="swift/pod-archive-onnxruntime-c-${ORT_POD_VERSION}.zip" - # xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' - # rm swift/pod-archive-onnxruntime-c-*.zip - # displayName: "Test Package.swift usage" + - script: | + set -e -x + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${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) + displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" # artifact: ios_packaging_artifacts From d28205a674ecaa4d0026d9d8883ddb0961685d06 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:54:49 -0700 Subject: [PATCH 24/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 4a55d70..480a0a2 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -19,6 +19,7 @@ jobs: variables: xcodeVersion: "14.3" + podArchive: "" timeoutInMinutes: 300 @@ -168,6 +169,7 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') + echo "##vso[task.setvariable variable=podArchive]${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From af0aec1a8f7a72075571c9209851020c8bee894b Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:56:14 -0700 Subject: [PATCH 25/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 480a0a2..3eadbcf 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -180,8 +180,8 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${POD_ARCHIVE}" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${{ variables.podArchive }}" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchive }}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: $(Build.SourcesDirectory) From f6361fe010d5862480efe672186ba13845ae1d7e Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 17:58:37 -0700 Subject: [PATCH 26/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 3eadbcf..6442e2d 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -170,7 +170,7 @@ jobs: ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') echo "##vso[task.setvariable variable=podArchive]${POD_ARCHIVE}" - shasum -a 256 "${POD_ARCHIVE}" + shasum -a 256 "${{ variables.podArchive }}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From 1ffd01c9019aa4308773662666ff904306ec7483 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 18:02:21 -0700 Subject: [PATCH 27/70] fix --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 6442e2d..294daea 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -19,7 +19,6 @@ jobs: variables: xcodeVersion: "14.3" - podArchive: "" timeoutInMinutes: 300 @@ -169,8 +168,8 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - echo "##vso[task.setvariable variable=podArchive]${POD_ARCHIVE}" - shasum -a 256 "${{ variables.podArchive }}" + echo "##vso[task.setvariable variable=${POD_ARCHIVE_NAME}]${POD_ARCHIVE}" + shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" @@ -180,8 +179,8 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${{ variables.podArchive }}" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchive }}" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${POD_ARCHIVE_NAME}" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_NAME}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: $(Build.SourcesDirectory) From 886c576722c975f438650c042f275f7b8d5770b6 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 18:04:03 -0700 Subject: [PATCH 28/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 294daea..c5537e9 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -168,7 +168,7 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - echo "##vso[task.setvariable variable=${POD_ARCHIVE_NAME}]${POD_ARCHIVE}" + echo "##vso[task.setvariable variable="POD_ARCHIVE_NAME"]${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From f8f9bcb3613f3c6559f4d080bdb22ca8691d82d6 Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 12 Jul 2023 18:07:53 -0700 Subject: [PATCH 29/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index c5537e9..608b861 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -168,7 +168,7 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - echo "##vso[task.setvariable variable="POD_ARCHIVE_NAME"]${POD_ARCHIVE}" + echo "##vso[task.setvariable variable='POD_ARCHIVE_NAME']${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From 2bb5e0cb3eef236d31dfab0b6620a72d685d8028 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 11:46:26 -0700 Subject: [PATCH 30/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 608b861..e5136a6 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -168,7 +168,7 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - echo "##vso[task.setvariable variable='POD_ARCHIVE_NAME']${POD_ARCHIVE}" + echo "##vso[task.setvariable variable=POD_ARCHIVE_NAME]${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' displayName: "Print ORT iOS Pod checksum" From 52c07aaf0b46783a04a21c9e0a4c3ece5d8527fe Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 11:49:18 -0700 Subject: [PATCH 31/70] update _full --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index e5136a6..a1ebb27 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -161,7 +161,7 @@ jobs: - script: | set -e -x ls - workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' + workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "List staged artifacts" - script: | @@ -170,7 +170,7 @@ jobs: POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') echo "##vso[task.setvariable variable=POD_ARCHIVE_NAME]${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE_NAME}" - workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts' + workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -179,7 +179,7 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts/${POD_ARCHIVE_NAME}" swift/ + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" swift/ export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_NAME}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip From 13e83aa0d066a79641d03b549955dee5c28ea422 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 12:16:25 -0700 Subject: [PATCH 32/70] fix --- .../github/mac-ios-swift-packaging-pipeline.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index a1ebb27..939c334 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -19,6 +19,7 @@ jobs: variables: xcodeVersion: "14.3" + podArchiveName: "" timeoutInMinutes: 300 @@ -167,9 +168,10 @@ jobs: - script: | set -e -x ARTIFACTS_LIST=$(ls) - POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') + POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') + echo ${POD_ARCHIVE} echo "##vso[task.setvariable variable=POD_ARCHIVE_NAME]${POD_ARCHIVE}" - shasum -a 256 "${POD_ARCHIVE_NAME}" + shasum -a 256 "$(POD_ARCHIVE_NAME)" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -179,8 +181,8 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_NAME}" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/$(POD_ARCHIVE_NAME)" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: $(Build.SourcesDirectory) From d1745432d1d5213c52a9a787f1365f459fae31bc Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 12:23:29 -0700 Subject: [PATCH 33/70] fix 2 --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 939c334..0060389 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -170,8 +170,8 @@ jobs: ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') echo ${POD_ARCHIVE} - echo "##vso[task.setvariable variable=POD_ARCHIVE_NAME]${POD_ARCHIVE}" - shasum -a 256 "$(POD_ARCHIVE_NAME)" + echo "##vso[task.setvariable variable=podArchiveName]${POD_ARCHIVE}" + shasum -a 256 "$(podArchiveName)" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" From 68d514749e869503cb880dca2246f7e286add3a9 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 12:27:14 -0700 Subject: [PATCH 34/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 0060389..3689a10 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -171,7 +171,7 @@ jobs: POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') echo ${POD_ARCHIVE} echo "##vso[task.setvariable variable=podArchiveName]${POD_ARCHIVE}" - shasum -a 256 "$(podArchiveName)" + shasum -a 256 "${POD_ARCHIVE}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" From a1595120013430967bbcec987072314e3e4a61f8 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 12:30:24 -0700 Subject: [PATCH 35/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 3689a10..3fae642 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -170,7 +170,7 @@ jobs: ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') echo ${POD_ARCHIVE} - echo "##vso[task.setvariable variable=podArchiveName]${POD_ARCHIVE}" + echo "##vso[task.setvariable variable=${{ variables.podArchiveName }}]${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -181,8 +181,8 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/$(POD_ARCHIVE_NAME)" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${{ variables.podArchiveName }}" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchiveName }}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: $(Build.SourcesDirectory) From 25c49b5987b52398b7691e786df9d1e949cb95c9 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 12:36:45 -0700 Subject: [PATCH 36/70] fix --- .../mac-ios-swift-packaging-pipeline.yml | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 3fae642..94b72a4 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -169,9 +169,8 @@ jobs: set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') - echo ${POD_ARCHIVE} - echo "##vso[task.setvariable variable=${{ variables.podArchiveName }}]${POD_ARCHIVE}" - shasum -a 256 "${POD_ARCHIVE}" + echo "##vso[task.setvariable variable=podArchiveName]${POD_ARCHIVE}" + shasum -a 256 "$(podArchiveName)" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -179,14 +178,14 @@ jobs: # 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 - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${{ variables.podArchiveName }}" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchiveName }}" - xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' - rm swift/pod-archive-onnxruntime-c-*.zip - workingDirectory: $(Build.SourcesDirectory) - displayName: "Test Package.swift usage" + # - script: | + # set -e -x + # cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/" swift/ + # export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchiveName }}" + # xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' + # rm swift/pod-archive-onnxruntime-c-*.zip + # workingDirectory: $(Build.SourcesDirectory) + # displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" # artifact: ios_packaging_artifacts From 3d7d8fbffd30c32484836db1712abe01a27dfe55 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:38:55 -0700 Subject: [PATCH 37/70] fix --- .../mac-ios-swift-packaging-pipeline.yml | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 94b72a4..45c739b 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -165,12 +165,21 @@ jobs: workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "List staged artifacts" - - script: | + - bash: | set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') - echo "##vso[task.setvariable variable=podArchiveName]${POD_ARCHIVE}" - shasum -a 256 "$(podArchiveName)" + + set_var() { + local VAR_NAME=${1:?} + local VAR_VALUE=${2:?} + echo "##vso[task.setvariable variable=${VAR_NAME}]${VAR_VALUE}" + echo "${VAR_NAME}: ${VAR_VALUE}" + } + + set_var "POD_ARCHIVE_NAME" ${POD_ARCHIVE}" + + shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -178,14 +187,14 @@ jobs: # 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 - # cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/" swift/ - # export ORT_IOS_POD_LOCAL_PATH="swift/${{ variables.podArchiveName }}" - # xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' - # rm swift/pod-archive-onnxruntime-c-*.zip - # workingDirectory: $(Build.SourcesDirectory) - # displayName: "Test Package.swift usage" + - script: | + set -e -x + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_NAME}" + xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' + rm swift/pod-archive-onnxruntime-c-*.zip + workingDirectory: $(Build.SourcesDirectory) + displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" # artifact: ios_packaging_artifacts From 83742a348f08697d79b095d31bdd852b887c2309 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:46:18 -0700 Subject: [PATCH 38/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 45c739b..0f8be5e 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -177,7 +177,7 @@ jobs: echo "${VAR_NAME}: ${VAR_VALUE}" } - set_var "POD_ARCHIVE_NAME" ${POD_ARCHIVE}" + set_var "POD_ARCHIVE_NAME" "${POD_ARCHIVE}" shasum -a 256 "${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' From b8cbb7c707301b23e606784a4664fc513a6cac98 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:49:14 -0700 Subject: [PATCH 39/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 0f8be5e..975a9b7 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -179,7 +179,7 @@ jobs: set_var "POD_ARCHIVE_NAME" "${POD_ARCHIVE}" - shasum -a 256 "${POD_ARCHIVE_NAME}" + shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" From 02dd7099cf0b50dd84435dee923fb0350e34b679 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:51:23 -0700 Subject: [PATCH 40/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 975a9b7..2f16518 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -179,7 +179,7 @@ jobs: set_var "POD_ARCHIVE_NAME" "${POD_ARCHIVE}" - shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" + shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "Print ORT iOS Pod checksum" @@ -189,8 +189,8 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE_NAME}" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE_NAME}" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" swift/ + export ORT_IOS_POD_LOCAL_PATH="swift/$(POD_ARCHIVE_NAME)" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: $(Build.SourcesDirectory) From 2bdfc0d75caf8b5184b4631348571d240dc7d5ab Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:56:27 -0700 Subject: [PATCH 41/70] fix --- .../mac-ios-swift-packaging-pipeline.yml | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 2f16518..b97ca38 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -165,32 +165,18 @@ jobs: workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' displayName: "List staged artifacts" - - bash: | + - script: | set -e -x ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') - set_var() { - local VAR_NAME=${1:?} - local VAR_VALUE=${2:?} - echo "##vso[task.setvariable variable=${VAR_NAME}]${VAR_VALUE}" - echo "${VAR_NAME}: ${VAR_VALUE}" - } - - set_var "POD_ARCHIVE_NAME" "${POD_ARCHIVE}" - - shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" - workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' - displayName: "Print ORT iOS Pod checksum" - + shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" # 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 - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/$(POD_ARCHIVE_NAME)" swift/ - export ORT_IOS_POD_LOCAL_PATH="swift/$(POD_ARCHIVE_NAME)" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${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) From ca3de4d9f19e30785aafcef68d575d4583d47b1e Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 13:57:49 -0700 Subject: [PATCH 42/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index b97ca38..5fc8b08 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -164,7 +164,11 @@ jobs: ls workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' 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 ARTIFACTS_LIST=$(ls) @@ -172,9 +176,6 @@ jobs: shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" - # 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 cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" swift/ export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' From 1d3185cceb45d3e134cbeec55e96e58ec3d16b08 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:00:43 -0700 Subject: [PATCH 43/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 5fc8b08..269b056 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -171,6 +171,7 @@ jobs: # once that's done cleanup the copy of the pod zip file - script: | set -e -x + cd "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full" ARTIFACTS_LIST=$(ls) POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') From 4b369e9ee935357de1cb69a0e9c6611fd4c1151b Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:04:43 -0700 Subject: [PATCH 44/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 269b056..e1868df 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -165,7 +165,6 @@ jobs: workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' 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 @@ -181,7 +180,6 @@ jobs: 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) displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" From f5be385c3aa9a4f9b87d00869e8a39255bbc65dc Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:08:13 -0700 Subject: [PATCH 45/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index e1868df..8010b39 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -175,8 +175,11 @@ jobs: POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" + + ls -R cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${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 From 65b05cb834c94ff0bf1ba80015e71768ad27da3a Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:12:17 -0700 Subject: [PATCH 46/70] update --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 8010b39..6d51d85 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -176,13 +176,12 @@ jobs: shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" - ls -R - - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" swift/ - - export ORT_IOS_POD_LOCAL_PATH="swift/${POD_ARCHIVE}" + ls -R "$(Build.SourcesDirectory)" + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" "$(Build.SourcesDirectory)/swift/" + export ORT_IOS_POD_LOCAL_PATH="$(Build.SourcesDirectory)/swift/${POD_ARCHIVE}" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip + displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" From 859c3e345ddf0ab14acff61c6997e27c7c1770c8 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:15:50 -0700 Subject: [PATCH 47/70] update --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 6d51d85..85485be 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -179,9 +179,10 @@ jobs: ls -R "$(Build.SourcesDirectory)" cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" "$(Build.SourcesDirectory)/swift/" export ORT_IOS_POD_LOCAL_PATH="$(Build.SourcesDirectory)/swift/${POD_ARCHIVE}" + + cd "$(Build.SourcesDirectory)" xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip - displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" From a2f312d30ef06b2382b9dd55a1f74e8f8e3ba475 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 13 Jul 2023 14:20:43 -0700 Subject: [PATCH 48/70] update --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 85485be..720d64c 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -176,13 +176,14 @@ jobs: shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" - ls -R "$(Build.SourcesDirectory)" - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" "$(Build.SourcesDirectory)/swift/" - export ORT_IOS_POD_LOCAL_PATH="$(Build.SourcesDirectory)/swift/${POD_ARCHIVE}" - cd "$(Build.SourcesDirectory)" + + cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${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)" displayName: "Test Package.swift usage" # - publish: "$(Build.ArtifactStagingDirectory)" From 9f58d76d7cc6fde97fcf294a4c21a658e68ac6b3 Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 11:45:08 -0700 Subject: [PATCH 49/70] sync repo source code with rel-1.15.0 and update yml files into two stages --- .gitignore | 4 +- Package.swift | 35 +-- objectivec/.DS_Store | Bin 6148 -> 0 bytes objectivec/cxx_api.h | 35 +-- objectivec/cxx_utils.h | 32 --- objectivec/cxx_utils.mm | 94 ------- objectivec/docs/jazzy_config.yaml | 13 + objectivec/docs/main_page.md | 5 + objectivec/docs/readme.md | 17 ++ objectivec/error_utils.h | 1 - objectivec/error_utils.mm | 8 - objectivec/include/onnxruntime.h | 3 +- .../include/ort_custom_op_registration.h | 23 -- objectivec/include/ort_env.h | 2 +- objectivec/include/ort_session.h | 36 +-- objectivec/ort_env.mm | 5 +- objectivec/ort_session.mm | 58 ++--- objectivec/ort_value.mm | 18 +- objectivec/ort_value_internal.h | 15 +- objectivec/test/assert_arc_enabled.mm | 4 + objectivec/test/assertion_utils.h | 32 +++ objectivec/test/ort_env_test.mm | 30 +++ objectivec/test/ort_session_test.mm | 243 ++++++++++++++++++ objectivec/test/ort_value_test.mm | 79 ++++++ objectivec/test/testdata/gen_models.sh | 12 + objectivec/test/testdata/single_add.basic.ort | Bin 0 -> 1296 bytes objectivec/test/testdata/single_add.onnx | Bin 0 -> 93 bytes objectivec/test/testdata/single_add_gen.py | 19 ++ .../mac-ios-swift-packaging-pipeline.yml | 206 +++++---------- 29 files changed, 577 insertions(+), 452 deletions(-) delete mode 100644 objectivec/.DS_Store delete mode 100644 objectivec/cxx_utils.h delete mode 100644 objectivec/cxx_utils.mm create mode 100644 objectivec/docs/jazzy_config.yaml create mode 100644 objectivec/docs/main_page.md create mode 100644 objectivec/docs/readme.md delete mode 100644 objectivec/include/ort_custom_op_registration.h create mode 100644 objectivec/test/assert_arc_enabled.mm create mode 100644 objectivec/test/assertion_utils.h create mode 100644 objectivec/test/ort_env_test.mm create mode 100644 objectivec/test/ort_session_test.mm create mode 100644 objectivec/test/ort_value_test.mm create mode 100755 objectivec/test/testdata/gen_models.sh create mode 100644 objectivec/test/testdata/single_add.basic.ort create mode 100644 objectivec/test/testdata/single_add.onnx create mode 100644 objectivec/test/testdata/single_add_gen.py diff --git a/.gitignore b/.gitignore index 2d7278a..e4772f9 100644 --- a/.gitignore +++ b/.gitignore @@ -398,4 +398,6 @@ FodyWeavers.xsd *.sln.iml .DS_Store -*.DS_Store \ No newline at end of file +*.DS_Store + +.build/ \ No newline at end of file diff --git a/Package.swift b/Package.swift index e7f008a..54609b1 100644 --- a/Package.swift +++ b/Package.swift @@ -32,14 +32,7 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - // exclude: ["test", "docs", "ReadMe.md", "format_objc.sh", - // "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"], + exclude: ["test", "docs", "ReadMe.md", "format_objc.sh"], cxxSettings: [ .define("SPM_BUILD"), .unsafeFlags(["-std=c++17", @@ -86,24 +79,10 @@ if let pod_archive_path = ProcessInfo.processInfo.environment["ORT_IOS_POD_LOCAL package.targets.append(Target.binaryTarget(name: "onnxruntime", path: pod_archive_path)) } else { - // When creating the release version: - // - remove the fatalError - // - uncomment the package.targets.append call - // - update the major/minor/patch version info in the url - // - insert the checksum info from the onnxruntime-ios-packaging-pipeline CI's 'Print ORT iOS Pod checksum' - // stage output (or download the pod archive artifact from the CI and run `shasum -a 256 ` - // to manually calculate it). - // The checksum length and chars should look something like - // "c89cd106ff02eb3892243acd7c4f2bd8e68c2c94f2751b5e35f98722e10c042b" - // - // package.targets.append( - // Target.binaryTarget(name: "onnxruntime", - // url: "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-.zip", - // checksum: "Insert checksum here") - // ) - - fatalError("It is not valid to use a non-release branch from https://github.com/microsoft/onnxruntime.\n" + - "Please use a release branch (e.g. rel-1.15.0), or build the ONNX Runtime iOS pod archive locally " + - "and set the ORT_IOS_POD_LOCAL_PATH environment variable.\n" + - "See Package.swift for more information on using a local pod archive.") + // 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") + ) } diff --git a/objectivec/.DS_Store b/objectivec/.DS_Store deleted file mode 100644 index 67f406eedd1fc62e6d3c050cee15d2acd30bd6a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyJ`bL3>+nf7}B^*xxbJ!TnYFu6&wD4?@g2RY+q-AkD5$ zbIVR~IsvftX?O-!0G4z|e0rFhKX;$mU1f|&=Q~aq@HTwx$JgVm`g+2-4>;f*dyGH% z$MHHrSt%d|q<|EV0#e{l3V83OEgusVrGONW0^bVw_o2}pd*PHApALo?0f-Bx!?=!F zg4jGk?1fVzGc-#oF{xG~h9#Z(R&~8_N=!Peh7YTgttJ$U)A{}u<*=TpCaDZOd9Q8s7rNJc(cQQX3PZGGVzgs!yd6J9 cQPwqI^La0v5`)fs(24pPa9w0l;J+0(1EVPwfB*mh diff --git a/objectivec/cxx_api.h b/objectivec/cxx_api.h index b57c865..3e4821c 100644 --- a/objectivec/cxx_api.h +++ b/objectivec/cxx_api.h @@ -11,30 +11,31 @@ #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 -#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(onnxruntime/x) -#else -#define ORT_C_CXX_HEADER_FILE_PATH(x) STRINGIFY(x) -#endif -// clang-format on +#include "onnxruntime/onnxruntime_c_api.h" +#include "onnxruntime/onnxruntime_cxx_api.h" -#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 - -#if __has_include(ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h)) +#if __has_include("onnxruntime/coreml_provider_factory.h") #define ORT_OBJC_API_COREML_EP_AVAILABLE 1 -#include ORT_C_CXX_HEADER_FILE_PATH(coreml_provider_factory.h) +#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__) diff --git a/objectivec/cxx_utils.h b/objectivec/cxx_utils.h deleted file mode 100644 index 0b3666d..0000000 --- a/objectivec/cxx_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#include -#include -#include - -#import "cxx_api.h" - -NS_ASSUME_NONNULL_BEGIN -@class ORTValue; - -namespace utils { - -NSString* toNSString(const std::string& str); -NSString* _Nullable toNullableNSString(const std::optional& str); - -std::string toStdString(NSString* str); -std::optional toStdOptionalString(NSString* _Nullable str); - -std::vector toStdStringVector(NSArray* strs); -NSArray* toNSStringNSArray(const std::vector& strs); - -NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& values, NSError** error); - -std::vector getWrappedCAPIOrtValues(NSArray* values); - -} // namespace utils - -NS_ASSUME_NONNULL_END diff --git a/objectivec/cxx_utils.mm b/objectivec/cxx_utils.mm deleted file mode 100644 index 01d0955..0000000 --- a/objectivec/cxx_utils.mm +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "cxx_utils.h" - -#include -#include -#include - -#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& str) { - if (str.has_value()) { - return toNSString(*str); - } - return nil; -} - -std::string toStdString(NSString* str) { - return std::string([str UTF8String]); -} - -std::optional toStdOptionalString(NSString* _Nullable str) { - if (str) { - return std::optional([str UTF8String]); - } - return std::nullopt; -} - -std::vector toStdStringVector(NSArray* strs) { - std::vector result; - result.reserve(strs.count); - for (NSString* str in strs) { - result.push_back([str UTF8String]); - } - return result; -} - -NSArray* toNSStringNSArray(const std::vector& strs) { - NSMutableArray* result = [NSMutableArray arrayWithCapacity:strs.size()]; - for (const std::string& str : strs) { - [result addObject:toNSString(str)]; - } - return result; -} - -NSArray* _Nullable wrapUnownedCAPIOrtValues(const std::vector& CAPIValues, NSError** error) { - NSMutableArray* 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 getWrappedCAPIOrtValues(NSArray* values) { - std::vector result; - result.reserve(values.count); - for (ORTValue* val in values) { - result.push_back(static_cast([val CXXAPIOrtValue])); - } - return result; -} - -} // namespace utils - -NS_ASSUME_NONNULL_END diff --git a/objectivec/docs/jazzy_config.yaml b/objectivec/docs/jazzy_config.yaml new file mode 100644 index 0000000..676f89d --- /dev/null +++ b/objectivec/docs/jazzy_config.yaml @@ -0,0 +1,13 @@ +module: ONNX Runtime Objective-C API +author: ONNX Runtime Authors +author_url: https://www.onnxruntime.ai +github_url: https://github.com/microsoft/onnxruntime + +objc: true +umbrella_header: ../include/onnxruntime.h +framework_root: .. + +readme: ./main_page.md + +hide_documentation_coverage: true +undocumented_text: "" diff --git a/objectivec/docs/main_page.md b/objectivec/docs/main_page.md new file mode 100644 index 0000000..fdc7c80 --- /dev/null +++ b/objectivec/docs/main_page.md @@ -0,0 +1,5 @@ +# ONNX Runtime Objective-C API + +ONNX Runtime provides an Objective-C API. + +It can be used from Objective-C/C++ or Swift with a bridging header. diff --git a/objectivec/docs/readme.md b/objectivec/docs/readme.md new file mode 100644 index 0000000..5697480 --- /dev/null +++ b/objectivec/docs/readme.md @@ -0,0 +1,17 @@ +# Objective-C API Documentation + +The API should be documented with comments in the [public header files](../include). + +## Documentation Generation + +The [Jazzy](https://github.com/realm/jazzy) tool is used to generate documentation from the code. + +To generate documentation, from the repo root, run: + +```bash +jazzy --config objectivec/docs/jazzy_config.yaml --output +``` + +The generated documentation website files will be in ``. + +[main_page.md](./main_page.md) contains content for the main page of the generated documentation website. diff --git a/objectivec/error_utils.h b/objectivec/error_utils.h index 4df71ce..274e74a 100644 --- a/objectivec/error_utils.h +++ b/objectivec/error_utils.h @@ -10,7 +10,6 @@ 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); diff --git a/objectivec/error_utils.mm b/objectivec/error_utils.mm index 335cf88..9186326 100644 --- a/objectivec/error_utils.mm +++ b/objectivec/error_utils.mm @@ -18,14 +18,6 @@ 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); } diff --git a/objectivec/include/onnxruntime.h b/objectivec/include/onnxruntime.h index c7bfe6f..c859f6a 100644 --- a/objectivec/include/onnxruntime.h +++ b/objectivec/include/onnxruntime.h @@ -5,9 +5,8 @@ // the headers below can also be imported individually #import "ort_coreml_execution_provider.h" -#import "ort_custom_op_registration.h" +#import "ort_xnnpack_execution_provider.h" #import "ort_enums.h" #import "ort_env.h" #import "ort_session.h" #import "ort_value.h" -#import "ort_xnnpack_execution_provider.h" diff --git a/objectivec/include/ort_custom_op_registration.h b/objectivec/include/ort_custom_op_registration.h deleted file mode 100644 index 8d50b92..0000000 --- a/objectivec/include/ort_custom_op_registration.h +++ /dev/null @@ -1,23 +0,0 @@ -// 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*/); diff --git a/objectivec/include/ort_env.h b/objectivec/include/ort_env.h index 8456b57..8c4184c 100644 --- a/objectivec/include/ort_env.h +++ b/objectivec/include/ort_env.h @@ -16,7 +16,7 @@ extern "C" { * * Available since 1.15. */ -NSString* _Nullable ORTVersion(void); +NSString* ORTVersion(void); #ifdef __cplusplus } diff --git a/objectivec/include/ort_session.h b/objectivec/include/ort_session.h index cfdb3bf..92269f4 100644 --- a/objectivec/include/ort_session.h +++ b/objectivec/include/ort_session.h @@ -3,7 +3,6 @@ #import -#import "ort_custom_op_registration.h" #import "ort_enums.h" NS_ASSUME_NONNULL_BEGIN @@ -197,19 +196,12 @@ NS_ASSUME_NONNULL_BEGIN * Available since 1.14. * * 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 + * 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. * - * @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. @@ -217,32 +209,6 @@ 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; - @end /** diff --git a/objectivec/ort_env.mm b/objectivec/ort_env.mm index 7043785..cd83ac5 100644 --- a/objectivec/ort_env.mm +++ b/objectivec/ort_env.mm @@ -12,8 +12,9 @@ NS_ASSUME_NONNULL_BEGIN -NSString* _Nullable ORTVersion(void) { - return [NSString stringWithUTF8String:OrtGetApiBase()->GetVersionString()]; +NSString* ORTVersion(void) { + std::string result = OrtGetApiBase()->GetVersionString(); + return [NSString stringWithUTF8String:result.c_str()]; } @implementation ORTEnv { diff --git a/objectivec/ort_session.mm b/objectivec/ort_session.mm index 0255e7b..c4f57b0 100644 --- a/objectivec/ort_session.mm +++ b/objectivec/ort_session.mm @@ -66,26 +66,22 @@ NS_ASSUME_NONNULL_BEGIN } std::vector inputNames, outputNames; - std::vector inputCAPIValues; - std::vector outputCAPIValues; + std::vector inputValues; + std::vector outputValues; - inputNames.reserve(inputs.count); - inputCAPIValues.reserve(inputs.count); for (NSString* inputName in inputs) { inputNames.push_back(inputName.UTF8String); - inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); } - outputNames.reserve(outputs.count); - outputCAPIValues.reserve(outputs.count); for (NSString* outputName in outputs) { outputNames.push_back(outputName.UTF8String); - outputCAPIValues.push_back(static_cast([outputs[outputName] CXXAPIOrtValue])); + outputValues.push_back(static_cast([outputs[outputName] CXXAPIOrtValue])); } Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], - inputNames.data(), inputCAPIValues.data(), inputNames.size(), - outputNames.data(), outputNames.size(), outputCAPIValues.data())); + inputNames.data(), inputValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputValues.data())); return YES; } @@ -107,39 +103,30 @@ NS_ASSUME_NONNULL_BEGIN NSArray* outputNameArray = outputNameSet.allObjects; std::vector inputNames, outputNames; - std::vector inputCAPIValues; - std::vector outputCAPIValues; + std::vector inputValues; + std::vector outputValues; - inputNames.reserve(inputs.count); - inputCAPIValues.reserve(inputs.count); for (NSString* inputName in inputs) { inputNames.push_back(inputName.UTF8String); - inputCAPIValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); } - outputNames.reserve(outputNameArray.count); - outputCAPIValues.reserve(outputNameArray.count); for (NSString* outputName in outputNameArray) { outputNames.push_back(outputName.UTF8String); - outputCAPIValues.push_back(nullptr); + outputValues.push_back(nullptr); } Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions], - inputNames.data(), inputCAPIValues.data(), inputNames.size(), - outputNames.data(), outputNames.size(), outputCAPIValues.data())); + inputNames.data(), inputValues.data(), inputNames.size(), + outputNames.data(), outputNames.size(), outputValues.data())); NSMutableDictionary* outputs = [[NSMutableDictionary alloc] init]; for (NSUInteger i = 0; i < outputNameArray.count; ++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 outputCXXAPIValue{outputCAPIValues[i]}; - ORTValue* outputValue = [[ORTValue alloc] initWithCXXAPIOrtValue:std::move(outputCXXAPIValue) - externalTensorData:nil - error:error]; + ORTValue* outputValue = [[ORTValue alloc] initWithCAPIOrtValue:outputValues[i] externalTensorData:nil error:error]; if (!outputValue) { - // 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]); + // 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; } @@ -309,19 +296,6 @@ 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(*_sessionOptions), - OrtGetApiBase())); - return YES; - } - ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error) -} - #pragma mark - Internal - (Ort::SessionOptions&)CXXAPIOrtSessionOptions { diff --git a/objectivec/ort_value.mm b/objectivec/ort_value.mm index f6ea674..ce77ca7 100644 --- a/objectivec/ort_value.mm +++ b/objectivec/ort_value.mm @@ -85,9 +85,9 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) { memoryInfo, tensorData.mutableBytes, tensorData.length, shapeVector.data(), shapeVector.size(), ONNXElementType); - return [self initWithCXXAPIOrtValue:std::move(ortValue) - externalTensorData:tensorData - error:error]; + return [self initWithCAPIOrtValue:ortValue.release() + externalTensorData:tensorData + error:error]; } ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error) } @@ -129,19 +129,17 @@ bool SafeMultiply(size_t a, size_t b, size_t& out) { #pragma mark - Internal -- (nullable instancetype)initWithCXXAPIOrtValue:(Ort::Value&&)existingCXXAPIOrtValue - externalTensorData:(nullable NSMutableData*)externalTensorData - error:(NSError**)error { +- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue + externalTensorData:(nullable NSMutableData*)externalTensorData + error:(NSError**)error { if ((self = [super init]) == nil) { return nil; } try { - _typeInfo = existingCXXAPIOrtValue.GetTypeInfo(); + _value = Ort::Value{CAPIOrtValue}; + _typeInfo = _value->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); diff --git a/objectivec/ort_value_internal.h b/objectivec/ort_value_internal.h index 6bc2e9b..345c0fc 100644 --- a/objectivec/ort_value_internal.h +++ b/objectivec/ort_value_internal.h @@ -9,18 +9,9 @@ NS_ASSUME_NONNULL_BEGIN @interface ORTValue () -/** - * 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; +- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue + externalTensorData:(nullable NSMutableData*)externalTensorData + error:(NSError**)error NS_DESIGNATED_INITIALIZER; - (Ort::Value&)CXXAPIOrtValue; diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm new file mode 100644 index 0000000..9aa0bad --- /dev/null +++ b/objectivec/test/assert_arc_enabled.mm @@ -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."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h new file mode 100644 index 0000000..f2b73e6 --- /dev/null +++ b/objectivec/test/assertion_utils.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#define ORTAssertNullableResultSuccessful(result, error) \ + do { \ + XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertBoolResultSuccessful(result, error) \ + do { \ + XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertNullableResultUnsuccessful(result, error) \ + do { \ + XCTAssertNil(result); \ + XCTAssertNotNil(error); \ + } while (0) + +#define ORTAssertBoolResultUnsuccessful(result, error) \ + do { \ + XCTAssertFalse(result); \ + XCTAssertNotNil(error); \ + } while (0) + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm new file mode 100644 index 0000000..420f55f --- /dev/null +++ b/objectivec/test/ort_env_test.mm @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_env.h" + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTEnvTest : XCTestCase +@end + +@implementation ORTEnvTest +- (void)testGetOrtVersion { + NSString* ver = ORTVersion(); + XCTAssertNotNil(ver); +} + +- (void)testInitOk { + NSError* err = nil; + ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(env, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm new file mode 100644 index 0000000..790ad1c --- /dev/null +++ b/objectivec/test/ort_session_test.mm @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_coreml_execution_provider.h" +#import "ort_xnnpack_execution_provider.h" +#import "ort_env.h" +#import "ort_session.h" +#import "ort_value.h" + +#import "test/assertion_utils.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTSessionTest : XCTestCase + +@property(readonly, nullable) ORTEnv* ortEnv; + +@end + +@implementation ORTSessionTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); +} + +- (void)tearDown { + _ortEnv = nil; + + [super tearDown]; +} + +// model with an Add op +// inputs: A, B +// output: C = A + B ++ (NSString*)getAddModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; + NSString* path = [bundle pathForResource:@"single_add.basic" + ofType:@"ort"]; + return path; +} + ++ (NSMutableData*)dataWithScalarFloat:(float)value { + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; + return data; +} + ++ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { + NSArray* shape = @[ @1 ]; + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeFloat + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + return ortValue; +} + ++ (ORTSessionOptions*)makeSessionOptions { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(sessionOptions, err); + return sessionOptions; +} + ++ (ORTRunOptions*)makeRunOptions { + NSError* err = nil; + ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(runOptions, err); + return runOptions; +} + +- (void)testInitAndRunWithPreallocatedOutputOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultSuccessful(runResult, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testInitAndRunOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSDictionary* outputs = + [session runWithInputs:@{@"A" : a, @"B" : b} + outputNames:[NSSet setWithArray:@[ @"C" ]] + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertNullableResultSuccessful(outputs, err); + + ORTValue* cOutput = outputs[@"C"]; + XCTAssertNotNil(cOutput); + + NSData* cData = [cOutput tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(cData, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testGetNamesOk { + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSArray* inputNames = [session inputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(inputNames, err); + XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); + + NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; + ORTAssertNullableResultSuccessful(overridableInitializerNames, err); + XCTAssertEqualObjects(overridableInitializerNames, (@[])); + + NSArray* outputNames = [session outputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(outputNames, err); + XCTAssertEqualObjects(outputNames, (@[ @"C" ])); +} + +- (void)testInitFailsWithInvalidPath { + NSString* invalidModelPath = @"invalid/path/to/model.ort"; + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:invalidModelPath + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultUnsuccessful(session, err); +} + +- (void)testRunFailsWithInvalidInput { + NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"D" : d} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultUnsuccessful(runResult, err); +} + +- (void)testAppendCoreMLEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; + coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option + + BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions + error:&err]; + + if (!ORTIsCoreMLExecutionProviderAvailable()) { + ORTAssertBoolResultUnsuccessful(appendResult, err); + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} + +- (void)testAppendXnnpackEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; + XnnpackOptions.intra_op_num_threads = 2; + + BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions + error:&err]; + // Without xnnpack EP in building also can pass the test + NSString* err_msg = [err localizedDescription]; + if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm new file mode 100644 index 0000000..734ad39 --- /dev/null +++ b/objectivec/test/ort_value_test.mm @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_value.h" + +#include + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTValueTest : XCTestCase +@end + +@implementation ORTValueTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; +} + +- (void)testInitTensorOk { + int32_t value = 42; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value + length:sizeof(int32_t)]; + NSArray* shape = @[ @1 ]; + + const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:elementType + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + + auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { + XCTAssertEqual(tensorInfo.elementType, elementType); + XCTAssertEqualObjects(tensorInfo.shape, shape); + }; + + ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(typeInfo, err); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); + checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); + + ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(tensorInfo, err); + checkTensorInfo(tensorInfo); + + NSData* actualData = [ortValue tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(actualData, err); + XCTAssertEqual(actualData.length, sizeof(int32_t)); + int32_t actualValue; + memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); + XCTAssertEqual(actualValue, value); +} + +- (void)testInitTensorFailsWithDataSmallerThanShape { + std::vector values{1, 2, 3, 4}; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() + length:values.size() * sizeof(int32_t)]; + NSArray* shape = @[ @2, @3 ]; // too large + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeInt32 + shape:shape + error:&err]; + ORTAssertNullableResultUnsuccessful(ortValue, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh new file mode 100755 index 0000000..0a58ca8 --- /dev/null +++ b/objectivec/test/testdata/gen_models.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Get directory this script is in +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd ${DIR} + +python3 ./single_add_gen.py + +ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort new file mode 100644 index 0000000000000000000000000000000000000000..f622784b35366ea8f0c33ccbdb513b5d6f7df7c1 GIT binary patch literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx new file mode 100644 index 0000000000000000000000000000000000000000..82e8fe669e0d84b6111f678b0742a552d820269b GIT binary patch literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py new file mode 100644 index 0000000..15b4372 --- /dev/null +++ b/objectivec/test/testdata/single_add_gen.py @@ -0,0 +1,19 @@ +import onnx +from onnx import TensorProto, helper + +graph = helper.make_graph( + [ # nodes + helper.make_node("Add", ["A", "B"], ["C"], "Add"), + ], + "SingleAdd", # name + [ # inputs + helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), + helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), + ], + [ # outputs + helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), + ], +) + +model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) +onnx.save(model, r"single_add.onnx") diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 720d64c..d7658fe 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -3,193 +3,111 @@ parameters: displayName: |- Type of build. "normal": A normal build not for publication. - type: string #TODO: add other build types name here + type: string #TODO: add other build types here values: - normal default: normal name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format -jobs: -- job: SPMIosPackaging - displayName: "SPM iOS Packaging" +stages: +- stage: SPM iOS local packaging testing + dependsOn: [] + jobs: + - job: SPMIosPackaging + displayName: "SPM iOS Packaging" pool: vmImage: "macOS-13" variables: xcodeVersion: "14.3" - podArchiveName: "" + artifactsNamne: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main timeoutInMinutes: 300 steps: - # - task: InstallAppleCertificate@2 - # inputs: - # certSecureFile: '$(ios_signing_certificate_name)' - # certPwd: '$(ios_signing_certificate_password)' - # keychain: 'temp' - # deleteCert: true - # displayName: 'Install ORT Mobile Test Signing Certificate' - - # - task: InstallAppleProvisioningProfile@1 - # inputs: - # provProfileSecureFile: '$(ios_provision_profile_name)' - # removeProfile: true - # displayName: 'Install ORT Mobile Test Provisioning Profile' - - - task: UsePythonVersion@0 - inputs: - versionSpec: "3.9" - addToPath: true - architecture: "x64" - - template: templates/use-xcode-version.yml parameters: xcodeVersion: ${{ variables.xcodeVersion }} - # - template: templates/install-appcenter.yml - - - script: | - pip install -r tools/ci_build/github/requirements.txt - displayName: "Install Python requirements" - - - bash: | - set -e - - BUILD_TYPE="${{ parameters.BuildType }}" - VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - BASE_VERSION="$(cat "${VERSION_FILE}")" - SHORT_COMMIT_HASH="$(git rev-parse --short HEAD)" - DEV_VERSION="${BASE_VERSION}-dev+$(Build.BuildNumber).${SHORT_COMMIT_HASH}" - - case "${BUILD_TYPE}" in - ("normal") - VERSION="${DEV_VERSION}"; SHOULD_UPLOAD_ARCHIVES="false" ;; - (*) - echo "Invalid build type: ${BUILD_TYPE}"; exit 1 ;; - esac - - # Do not output ##vso[] commands with `set -x` or they may be parsed again and include a trailing quote. - set +x - - set_var() { - local VAR_NAME=${1:?} - local VAR_VALUE=${2:?} - echo "##vso[task.setvariable variable=${VAR_NAME}]${VAR_VALUE}" - echo "${VAR_NAME}: ${VAR_VALUE}" - } - - set_var "ORT_POD_VERSION" "${VERSION}" - set_var "ORT_SHOULD_UPLOAD_ARCHIVES" "${SHOULD_UPLOAD_ARCHIVES}" - displayName: "Set variables" - - # - script: | - # $(Build.SourcesDirectory)/tools/ci_build/github/scripts/install_protobuf.sh -p $(Build.BinariesDirectory)/protobuf_install -d $(Build.SourcesDirectory)/cmake/deps.txt - # displayName: "Build Host Protoc" - - # # create and test full pods - # - script: | - # python tools/ci_build/github/scripts/build_and_assemble_ios_pods.py \ - # --build-dir "$(Build.BinariesDirectory)/ios_framework_full" \ - # --staging-dir "$(Build.BinariesDirectory)/staging" \ - # --pod-version "${ORT_POD_VERSION}" \ - # --test \ - # --variant Full \ - # --build-settings-file tools/ci_build/github/default_full_ios_framework_build_settings.json \ - # -b="--path_to_protoc_exe" -b "$(Build.BinariesDirectory)/protobuf_install/bin/protoc" - # displayName: "[Full] Build iOS framework and assemble pod package files" - - # - script: | - # python tools/ci_build/github/scripts/test_ios_packages.py \ - # --fail_if_cocoapods_missing \ - # --framework_info_file "$(Build.BinariesDirectory)/ios_framework_full/framework_info.json" \ - # --c_framework_dir "$(Build.BinariesDirectory)/ios_framework_full/framework_out" \ - # --variant Full \ - # --test_project_stage_dir "$(Build.BinariesDirectory)/app_center_test_full" \ - # --prepare_test_project_only - # displayName: "[Full] Assemble test project for App Center" - - # - task: Xcode@5 - # inputs: - # actions: 'build-for-testing' - # configuration: 'Debug' - # xcWorkspacePath: '$(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ios_package_test.xcworkspace' - # sdk: 'iphoneos' - # scheme: 'ios_package_test' - # signingOption: 'manual' - # signingIdentity: '$(APPLE_CERTIFICATE_SIGNING_IDENTITY)' - # provisioningProfileName: 'iOS Team Provisioning Profile' - # args: '-derivedDataPath $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData' - # workingDirectory: $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/ - # displayName: '[Full] Build iphone arm64 tests' - - # - script: | - # set -e -x - # appcenter test run xcuitest \ - # --app "AI-Frameworks/ORT-Mobile-iOS" \ - # --devices $(app_center_test_devices) \ - # --test-series "master" \ - # --locale "en_US" \ - # --build-dir $(Build.BinariesDirectory)/app_center_test_full/ios_package_test/DerivedData/Build/Products/Debug-iphoneos \ - # --token $(app_center_api_token) - # displayName: "[Full] Run E2E tests on App Center" - - # - task: AzureCLI@2 - # inputs: - # azureSubscription: 'AIInfraBuildOnnxRuntimeOSS' - # scriptType: 'bash' - # scriptLocation: 'scriptPath' - # scriptPath: 'tools/ci_build/github/apple/assemble_ios_packaging_artifacts.sh' - # arguments: >- - # "$(Build.BinariesDirectory)/staging" - # "$(Build.ArtifactStagingDirectory)" - # "$(ORT_POD_VERSION)" - # "$(ORT_SHOULD_UPLOAD_ARCHIVES)" - # displayName: "Assemble artifacts" - - # TODO: Download artifacts from the onnxruntime-ios-packaging pipeline artifacts folder - - # Download artifacts from a specific pipeline. + # Download artifacts from a specific pipeline + # For now, it consumes rel-1.15.0 version ORT iOS Pod which matches the current source code - task: DownloadPipelineArtifact@2 inputs: buildType: 'specific' project: 'Lotus' definition: 995 - buildVersionToDownload: 'latest' + buildVersionToDownload: 'latestFromBranch' + branchName: 'rel-1.15.0' targetPath: '$(Build.ArtifactStagingDirectory)' - script: | set -e -x ls - workingDirectory: '$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full' + 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)/ios_packaging_artifacts_full" + cd "$(Build.ArtifactStagingDirectory)/$(artifactsName)" ARTIFACTS_LIST=$(ls) - POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '3p') + POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - shasum -a 256 "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" + shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" cd "$(Build.SourcesDirectory)" - - cp "$(Build.ArtifactStagingDirectory)/ios_packaging_artifacts_full/${POD_ARCHIVE}" swift/ + 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)" - displayName: "Test Package.swift usage" + displayName: "Print ORT iOS Pod checksum and test Package.swift usage" - # - publish: "$(Build.ArtifactStagingDirectory)" - # artifact: ios_packaging_artifacts - # displayName: "Publish artifacts" + - publish: "$(Build.ArtifactStagingDirectory)/$(artifactName)" + artifact: ios_packaging_artifacts + displayName: "Publish artifacts" - # - template: templates/component-governance-component-detection-steps.yml - # parameters : - # condition : 'succeeded' + - template: templates/component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' + + - stage: SPM iOS release packaging testing + dependsOn: [] + jobs: + - job: SPMIosPackaging + displayName: "SPM iOS Packaging" + + pool: + vmImage: "macOS-13" + + variables: + xcodeVersion: "14.3" + + timeoutInMinutes: 300 + + steps: + - template: templates/use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} + + - script: | + set -e -x + VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + SPM_POD_VERSION="$(cat "${VERSION_FILE}")" + shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + workingDirectory: "$(Build.SourcesDirectory)" + displayName: "Print ORT iOS Release Pod checksum" + + - 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' From 25ef7acc605e4acbfc3b288df1530fb2a4b4851e Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 11:56:20 -0700 Subject: [PATCH 50/70] format yml --- .../mac-ios-swift-packaging-pipeline.yml | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index d7658fe..ffe6fbe 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -17,75 +17,12 @@ stages: - job: SPMIosPackaging displayName: "SPM iOS Packaging" - pool: - vmImage: "macOS-13" - - variables: - xcodeVersion: "14.3" - artifactsNamne: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main - - timeoutInMinutes: 300 - - steps: - - template: templates/use-xcode-version.yml - parameters: - xcodeVersion: ${{ variables.xcodeVersion }} - - # Download artifacts from a specific pipeline - # For now, it consumes rel-1.15.0 version ORT iOS Pod which matches the current source code - - task: DownloadPipelineArtifact@2 - inputs: - buildType: 'specific' - project: 'Lotus' - definition: 995 - buildVersionToDownload: 'latestFromBranch' - branchName: 'rel-1.15.0' - 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)" - ARTIFACTS_LIST=$(ls) - POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') - - shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" - - cd "$(Build.SourcesDirectory)" - 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)" - displayName: "Print ORT iOS Pod checksum and test Package.swift usage" - - - publish: "$(Build.ArtifactStagingDirectory)/$(artifactName)" - artifact: ios_packaging_artifacts - displayName: "Publish artifacts" - - - template: templates/component-governance-component-detection-steps.yml - parameters : - condition : 'succeeded' - - - stage: SPM iOS release packaging testing - dependsOn: [] - jobs: - - job: SPMIosPackaging - displayName: "SPM iOS Packaging" - pool: vmImage: "macOS-13" variables: xcodeVersion: "14.3" + artifactsNamne: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main timeoutInMinutes: 300 @@ -94,20 +31,83 @@ stages: parameters: xcodeVersion: ${{ variables.xcodeVersion }} - - script: | - set -e -x - VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - SPM_POD_VERSION="$(cat "${VERSION_FILE}")" - shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Print ORT iOS Release Pod checksum" + # Download artifacts from a specific pipeline + # For now, it consumes rel-1.15.0 version ORT iOS Pod which matches the current source code + - task: DownloadPipelineArtifact@2 + inputs: + buildType: 'specific' + project: 'Lotus' + definition: 995 + buildVersionToDownload: 'latestFromBranch' + branchName: 'rel-1.15.0' + 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)" + ARTIFACTS_LIST=$(ls) + POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') + + shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" + + cd "$(Build.SourcesDirectory)" + 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)" - displayName: "Test Package.swift usage" + displayName: "Print ORT iOS Pod checksum and test Package.swift usage" + + - publish: "$(Build.ArtifactStagingDirectory)/$(artifactName)" + artifact: ios_packaging_artifacts + displayName: "Publish artifacts" - template: templates/component-governance-component-detection-steps.yml parameters : condition : 'succeeded' + + - stage: SPM iOS release packaging testing + dependsOn: [] + jobs: + - job: SPMIosPackaging + displayName: "SPM iOS Packaging" + + pool: + vmImage: "macOS-13" + + variables: + xcodeVersion: "14.3" + + timeoutInMinutes: 300 + + steps: + - template: templates/use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} + + - script: | + set -e -x + VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + SPM_POD_VERSION="$(cat "${VERSION_FILE}")" + shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + workingDirectory: "$(Build.SourcesDirectory)" + displayName: "Print ORT iOS Release Pod checksum" + + - 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' From 6c53f44d9e587c6ff46b8a66c7d730c9f471f6dc Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 12:01:13 -0700 Subject: [PATCH 51/70] remove scripts files not needed any more --- cmake/deps.txt | 44 ---- swift/.DS_Store | Bin 6148 -> 0 bytes swift/OnnxRuntimeBindingsTests/.DS_Store | Bin 6148 -> 0 bytes ...ult_full_ios_framework_build_settings.json | 22 -- tools/ci_build/github/requirements.txt | 1 - .../github/scripts/assemble_c_pod_package.py | 155 ------------- .../scripts/assemble_objc_pod_package.py | 212 ------------------ .../scripts/build_and_assemble_ios_pods.py | 185 --------------- .../github/scripts/install_protobuf.sh | 59 ----- .../github/scripts/package_assembly_utils.py | 130 ----------- .../github/scripts/test_ios_packages.py | 192 ---------------- .../github/templates/install-appcenter.yml | 12 - 12 files changed, 1012 deletions(-) delete mode 100644 cmake/deps.txt delete mode 100644 swift/.DS_Store delete mode 100644 swift/OnnxRuntimeBindingsTests/.DS_Store delete mode 100644 tools/ci_build/github/default_full_ios_framework_build_settings.json delete mode 100644 tools/ci_build/github/requirements.txt delete mode 100644 tools/ci_build/github/scripts/assemble_c_pod_package.py delete mode 100755 tools/ci_build/github/scripts/assemble_objc_pod_package.py delete mode 100644 tools/ci_build/github/scripts/build_and_assemble_ios_pods.py delete mode 100644 tools/ci_build/github/scripts/install_protobuf.sh delete mode 100644 tools/ci_build/github/scripts/package_assembly_utils.py delete mode 100644 tools/ci_build/github/scripts/test_ios_packages.py delete mode 100644 tools/ci_build/github/templates/install-appcenter.yml diff --git a/cmake/deps.txt b/cmake/deps.txt deleted file mode 100644 index 63bdf21..0000000 --- a/cmake/deps.txt +++ /dev/null @@ -1,44 +0,0 @@ -#Name;Url;SHA1 -#This is a CSV file. -#The columns are separated by ";" because a list in cmake is just a ";" separated group of strings. -#Names should be in lower case. They will be used as variable names in cmake. -#URLs can be either https URLs or local file paths in cmake-style(directory separator is a forward slash character). -#SHA1 hashes can be generated by running sha1sum command. -#If you need to change abseil's version to a different one, you may also want to update external\abseil-cpp.natvis -#since the file contains a version string: "lts_20220623". However, the file is for debugging purposes only and would -#not affect built binaries. -abseil_cpp;https://github.com/abseil/abseil-cpp/archive/refs/tags/20220623.1.zip;50c137c88965cba015dfcc8fd5d9b46d23146751 -cxxopts;https://github.com/jarro2783/cxxopts/archive/3c73d91c0b04e2b59462f0a741be8c07024c1bc0.zip;6c6ca7f8480b26c8d00476e0e24b7184717fe4f0 -date;https://github.com/HowardHinnant/date/archive/refs/tags/v2.4.1.zip;ea99f021262b1d804a872735c658860a6a13cc98 -dlpack;https://github.com/dmlc/dlpack/archive/refs/tags/v0.6.zip;4d565dd2e5b31321e5549591d78aa7f377173445 -flatbuffers;https://github.com/google/flatbuffers/archive/refs/tags/v1.12.0.zip;ba0a75fd12dbef8f6557a74e611b7a3d0c5fe7bf -fp16;https://github.com/Maratyszcza/FP16/archive/0a92994d729ff76a58f692d3028ca1b64b145d91.zip;b985f6985a05a1c03ff1bb71190f66d8f98a1494 -fxdiv;https://github.com/Maratyszcza/FXdiv/archive/63058eff77e11aa15bf531df5dd34395ec3017c8.zip;a5658f4036402dbca7cebee32be57fb8149811e1 -google_benchmark;https://github.com/google/benchmark/archive/refs/tags/v1.7.0.zip;e97c368b176e8614e3f1bf13dd9abcf6a7ad9908 -google_nsync;https://github.com/google/nsync/archive/refs/tags/1.23.0.zip;f3233450cf7156fc0bedd1b0e884eddec264897c -googletest;https://github.com/google/googletest/archive/519beb0e52c842729b4b53731d27c0e0c32ab4a2.zip;4b3c37972e4c1bef1185d46f702082f8772ee73f -googlexnnpack;https://github.com/google/XNNPACK/archive/003c580e696a774afdc984996ee909b7c8d8128c.zip;9f192e3f15e1e37ae9c78d53eeea47e45c5eb31c -json;https://github.com/nlohmann/json/archive/refs/tags/v3.10.5.zip;f257f8dc27c5b8c085dc887b40cddd18ae1f725c -microsoft_gsl;https://github.com/microsoft/GSL/archive/refs/tags/v4.0.0.zip;cf368104cd22a87b4dd0c80228919bb2df3e2a14 -microsoft_wil;https://github.com/microsoft/wil/archive/5f4caba4e7a9017816e47becdd918fcc872039ba.zip;fd119887d0d17c37adf1fc227b054befa28158ad -mimalloc;https://github.com/microsoft/mimalloc/archive/refs/tags/v2.1.1.zip;d5ee7d34223d0567892db5179849939c8769dc41 -mp11;https://github.com/boostorg/mp11/archive/refs/tags/boost-1.79.0.zip;c8f04e378535ededbe5af52c8f969d2dedbe73d5 -onnx;https://github.com/onnx/onnx/archive/refs/tags/v1.14.0.zip;3c6e43a36f94addc15afe939860127a1d74a9488 -#use the last commit of 8.6-GA branch (https://github.com/onnx/onnx-tensorrt/commit/6ba67d3428e05f690145373ca87fb8d32f98df45) -onnx_tensorrt;https://github.com/onnx/onnx-tensorrt/archive/6ba67d3428e05f690145373ca87fb8d32f98df45.zip;805902b4f03f09f07151e03b5ccc49968c9cc896 -protobuf;https://github.com/protocolbuffers/protobuf/archive/refs/tags/v21.12.zip;7cf2733949036c7d52fda017badcab093fe73bfa -protoc_win64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win64.zip;b4521f7ada5b260380f94c4bd7f1b7684c76969a -protoc_win32;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win32.zip;3688010318192c46ce73213cdfb6b3e5656da874 -protoc_linux_x64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_64.zip;338462004aa5be9fba45b35b5b4be43f69b47a90 -protoc_linux_x86;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-x86_32.zip;61fdbe7d6360e065ec6fea23bca2cca673115fb8 -protoc_linux_aarch64;https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-linux-aarch_64.zip;df9d45470b0b8cf939dd2f0ec6b88e9cafc4d617 -psimd;https://github.com/Maratyszcza/psimd/archive/072586a71b55b7f8c584153d223e95687148a900.zip;1f5454b01f06f9656b77e4a5e2e31d7422487013 -pthreadpool;https://github.com/Maratyszcza/pthreadpool/archive/1787867f6183f056420e532eec640cba25efafea.zip;e43e80781560c5ab404a4da20f34d846f5f5d101 -pybind11;https://github.com/pybind/pybind11/archive/refs/tags/v2.10.1.zip;769b6aa67a77f17a770960f604b727645b6f6a13 -pytorch_cpuinfo;https://github.com/pytorch/cpuinfo/archive/5916273f79a21551890fd3d56fc5375a78d1598d.zip;2be4d2ae321fada97cb39eaf4eeba5f8c85597cf -re2;https://github.com/google/re2/archive/refs/tags/2022-06-01.zip;aa77313b76e91b531ee7f3e45f004c6a502a5374 -safeint;https://github.com/dcleblanc/SafeInt/archive/ff15c6ada150a5018c5ef2172401cb4529eac9c0.zip;913a4046e5274d329af2806cb53194f617d8c0ab -tensorboard;https://github.com/tensorflow/tensorboard/archive/373eb09e4c5d2b3cc2493f0949dc4be6b6a45e81.zip;67b833913605a4f3f499894ab11528a702c2b381 -cutlass;https://github.com/NVIDIA/cutlass/archive/refs/tags/v3.0.0.zip;0f95b3c1fc1bd1175c4a90b2c9e39074d1bccefd -extensions;https://github.com/microsoft/onnxruntime-extensions/archive/94142d8391c9791ec71c38336436319a2d4ac7a0.zip;4365ac5140338b4cb75a39944a4be276e3829b3c -eigen;https://gitlab.com/libeigen/eigen/-/archive/3.4/eigen-3.4.zip;ee201b07085203ea7bd8eb97cbcb31b07cfa3efb \ No newline at end of file diff --git a/swift/.DS_Store b/swift/.DS_Store deleted file mode 100644 index f42f1cf4750f83663b0b9f590b707e97ea259a51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKyH3ME5S)b+k!Vt;ykE#4oUBks0zLo{M+hl6g%gR=9ly=&gD92*B?a1*cE`8g zxzkPI^#YLQ)UJR9fH_?epBkp7@6{)E6B!}WxyJ)e=y1dv-Y3=96Utp;Lso~65r2n< z`*dh6zM{tyc8o{#ZNJ^W91i>ITV^&DNCi@XR3H^d1%6RLdoOK%=a?}SNCi@XvjX~k zD0IadI5^s;gTY1s;*4oCKHDroESezJz`>CjnmCo{REZHooX&iSx*9k*IvoxNf~-a5IQ_S!;! srhgl2t(?JHG0|Ev7ut%K7j;FS`Mw4Yjz(wR=*0XHP+ihefxl4T3q58UfB*mh diff --git a/swift/OnnxRuntimeBindingsTests/.DS_Store b/swift/OnnxRuntimeBindingsTests/.DS_Store deleted file mode 100644 index 2669ebf3d77440c8d1f59febf92f2a487412ef29..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKF=_)r43rWV4sKkg+%NbCi*Y_+e;~w8XE?BNe^uUzna$xu`(T(FpVKGyP#Fip@s5j~Y;W&&KAb1j_Y>qk*_Ip|zVr9T zw_!NmCn+lhq<|EV0#ZN<{8|C_Uf6t*s3--bfE2hY!0$tY6MNy97@rP=7y*DYq{Fa| zSpwLY0QSN$5gC{#6_`}75yO*?e5<-%I3_0DyoL|2lf5PskJIt~7UkwWQBev=fm;P0 zbGu~!e}Vrn|KF0dlLAuUUn$_T&2F>Cm8!Q+F2`Qm;IDAje8Op12L&P8F)-ROHf+bw cQIvI!Ydr6TV`9*e4?0jk1Jp$(1^!xrFAN41od5s; diff --git a/tools/ci_build/github/default_full_ios_framework_build_settings.json b/tools/ci_build/github/default_full_ios_framework_build_settings.json deleted file mode 100644 index fd07074..0000000 --- a/tools/ci_build/github/default_full_ios_framework_build_settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "build_osx_archs": { - "iphoneos": [ - "arm64" - ], - "iphonesimulator": [ - "arm64", - "x86_64" - ] - }, - "build_params": [ - "--ios", - "--parallel", - "--use_xcode", - "--build_apple_framework", - "--use_coreml", - "--skip_tests", - "--cmake_extra_defines=onnxruntime_BUILD_UNIT_TESTS=OFF", - "--apple_deploy_target=12.0", - "--use_xnnpack" - ] -} diff --git a/tools/ci_build/github/requirements.txt b/tools/ci_build/github/requirements.txt deleted file mode 100644 index adf11d6..0000000 --- a/tools/ci_build/github/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -flatbuffers diff --git a/tools/ci_build/github/scripts/assemble_c_pod_package.py b/tools/ci_build/github/scripts/assemble_c_pod_package.py deleted file mode 100644 index 14e7729..0000000 --- a/tools/ci_build/github/scripts/assemble_c_pod_package.py +++ /dev/null @@ -1,155 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import pathlib -import shutil -import sys - -_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) -sys.path.append(str(_script_dir.parent)) - - -from package_assembly_utils import ( # noqa: E402 - PackageVariant, - copy_repo_relative_to_dir, - gen_file_from_template, - load_json_config, -) - - -def get_pod_config_file(package_variant: PackageVariant): - """ - Gets the pod configuration file path for the given package variant. - """ - if package_variant == PackageVariant.Full: - return _script_dir / "onnxruntime-c.config.json" - elif package_variant == PackageVariant.Mobile: - return _script_dir / "onnxruntime-mobile-c.config.json" - elif package_variant == PackageVariant.Test: - return _script_dir / "onnxruntime-test-c.config.json" - elif package_variant == PackageVariant.Training: - return _script_dir / "onnxruntime-training-c.config.json" - else: - raise ValueError(f"Unhandled package variant: {package_variant}") - - -def assemble_c_pod_package( - staging_dir: pathlib.Path, - pod_version: str, - framework_info_file: pathlib.Path, - public_headers_dir: pathlib.Path, - framework_dir: pathlib.Path, - package_variant: PackageVariant, -): - """ - Assembles the files for the C/C++ pod package in a staging directory. - - :param staging_dir Path to the staging directory for the C/C++ pod files. - :param pod_version C/C++ pod version. - :param framework_info_file Path to the framework_info.json file containing additional values for the podspec. - :param public_headers_dir Path to the public headers directory to include in the pod. - :param framework_dir Path to the onnxruntime framework directory to include in the pod. - :param package_variant The pod package variant. - :return Tuple of (package name, path to the podspec file). - """ - staging_dir = staging_dir.resolve() - framework_info_file = framework_info_file.resolve(strict=True) - public_headers_dir = public_headers_dir.resolve(strict=True) - framework_dir = framework_dir.resolve(strict=True) - - framework_info = load_json_config(framework_info_file) - pod_config = load_json_config(get_pod_config_file(package_variant)) - - pod_name = pod_config["name"] - - print(f"Assembling files in staging directory: {staging_dir}") - if staging_dir.exists(): - print("Warning: staging directory already exists", file=sys.stderr) - - # copy the necessary files to the staging directory - shutil.copytree(framework_dir, staging_dir / framework_dir.name, dirs_exist_ok=True) - shutil.copytree(public_headers_dir, staging_dir / public_headers_dir.name, dirs_exist_ok=True) - copy_repo_relative_to_dir(["LICENSE"], staging_dir) - - # generate the podspec file from the template - variable_substitutions = { - "DESCRIPTION": pod_config["description"], - "IOS_DEPLOYMENT_TARGET": framework_info["IOS_DEPLOYMENT_TARGET"], - "LICENSE_FILE": "LICENSE", - "NAME": pod_name, - "ORT_C_FRAMEWORK": framework_dir.name, - "ORT_C_HEADERS_DIR": public_headers_dir.name, - "SUMMARY": pod_config["summary"], - "VERSION": pod_version, - "WEAK_FRAMEWORK": framework_info["WEAK_FRAMEWORK"], - } - - podspec_template = _script_dir / "c.podspec.template" - podspec = staging_dir / f"{pod_name}.podspec" - - gen_file_from_template(podspec_template, podspec, variable_substitutions) - - return pod_name, podspec - - -def parse_args(): - parser = argparse.ArgumentParser( - description=""" - Assembles the files for the C/C++ pod package in a staging directory. - This directory can be validated (e.g., with `pod lib lint`) and then zipped to create a package for release. - """ - ) - - parser.add_argument( - "--staging-dir", - type=pathlib.Path, - default=pathlib.Path("./c-staging"), - help="Path to the staging directory for the C/C++ pod files.", - ) - parser.add_argument("--pod-version", required=True, help="C/C++ pod version.") - parser.add_argument( - "--framework-info-file", - type=pathlib.Path, - required=True, - help="Path to the framework_info.json file containing additional values for the podspec. " - "This file should be generated by CMake in the build directory.", - ) - parser.add_argument( - "--public-headers-dir", - type=pathlib.Path, - required=True, - help="Path to the public headers directory to include in the pod.", - ) - parser.add_argument( - "--framework-dir", - type=pathlib.Path, - required=True, - help="Path to the onnxruntime framework directory to include in the pod.", - ) - parser.add_argument( - "--variant", choices=PackageVariant.all_variant_names(), required=True, help="Pod package variant." - ) - - return parser.parse_args() - - -def main(): - args = parse_args() - - assemble_c_pod_package( - staging_dir=args.staging_dir, - pod_version=args.pod_version, - framework_info_file=args.framework_info_file, - public_headers_dir=args.public_headers_dir, - framework_dir=args.framework_dir, - package_variant=PackageVariant[args.variant], - ) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/ci_build/github/scripts/assemble_objc_pod_package.py b/tools/ci_build/github/scripts/assemble_objc_pod_package.py deleted file mode 100755 index 709c7ea..0000000 --- a/tools/ci_build/github/scripts/assemble_objc_pod_package.py +++ /dev/null @@ -1,212 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import pathlib -import sys - -_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) -sys.path.append(str(_script_dir.parent)) - - -from assemble_c_pod_package import get_pod_config_file as get_c_pod_config_file # noqa: E402 -from package_assembly_utils import ( # noqa: E402 - PackageVariant, - copy_repo_relative_to_dir, - filter_files, - gen_file_from_template, - load_json_config, -) - -# these variables contain paths or path patterns that are relative to the repo root - -# the license file -license_file = "LICENSE" - -# include directories for compiling the pod itself -include_dirs = [ - "objectivec", -] - -all_objc_files = { - "source_files": [ - "objectivec/include/*.h", - "objectivec/*.h", - "objectivec/*.m", - "objectivec/*.mm", - ], - "public_header_files": [ - "objectivec/include/*.h", - ], - "test_source_files": [ - "objectivec/test/*.h", - "objectivec/test/*.m", - "objectivec/test/*.mm", - ], - "test_resource_files": [ - "objectivec/test/testdata/*.ort", - "onnxruntime/test/testdata/training_api/*", - ], -} - -training_only_objc_files = { - "source_files": [ - "objectivec/include/onnxruntime_training.h", - "objectivec/include/ort_checkpoint.h", - "objectivec/include/ort_training_session.h", - "objectivec/ort_checkpoint.mm", - "objectivec/ort_checkpoint_internal.h", - "objectivec/ort_training_session_internal.h", - "objectivec/ort_training_session.mm", - ], - "public_header_files": [ - "objectivec/include/ort_checkpoint.h", - "objectivec/include/ort_training_session.h", - "objectivec/include/onnxruntime_training.h", - ], - "test_source_files": [ - "objectivec/test/ort_training_session_test.mm", - "objectivec/test/ort_checkpoint_test.mm", - "objectivec/test/ort_training_utils_test.mm", - ], - "test_resource_files": [ - "onnxruntime/test/testdata/training_api/*", - ], -} - - -def get_pod_files(package_variant: PackageVariant): - """ - Gets the source and header files for the given package variant. - """ - if package_variant == PackageVariant.Training: - return all_objc_files - else: - # return files that are in pod_files but not in training_only_objc_files - filtered_pod_files = {} - for key in all_objc_files: - filtered_pod_files[key] = filter_files(all_objc_files[key], training_only_objc_files[key]) - return filtered_pod_files - - -def get_pod_config_file(package_variant: PackageVariant): - """ - Gets the pod configuration file path for the given package variant. - """ - if package_variant == PackageVariant.Full: - return _script_dir / "onnxruntime-objc.config.json" - elif package_variant == PackageVariant.Mobile: - return _script_dir / "onnxruntime-mobile-objc.config.json" - elif package_variant == PackageVariant.Training: - return _script_dir / "onnxruntime-training-objc.config.json" - else: - raise ValueError(f"Unhandled package variant: {package_variant}") - - -def assemble_objc_pod_package( - staging_dir: pathlib.Path, pod_version: str, framework_info_file: pathlib.Path, package_variant: PackageVariant -): - """ - Assembles the files for the Objective-C pod package in a staging directory. - - :param staging_dir Path to the staging directory for the Objective-C pod files. - :param pod_version Objective-C pod version. - :param framework_info_file Path to the framework_info.json file containing additional values for the podspec. - :param package_variant The pod package variant. - :return Tuple of (package name, path to the podspec file). - """ - staging_dir = staging_dir.resolve() - framework_info_file = framework_info_file.resolve(strict=True) - - framework_info = load_json_config(framework_info_file) - pod_config = load_json_config(get_pod_config_file(package_variant)) - c_pod_config = load_json_config(get_c_pod_config_file(package_variant)) - - pod_name = pod_config["name"] - - print(f"Assembling files in staging directory: {staging_dir}") - if staging_dir.exists(): - print("Warning: staging directory already exists", file=sys.stderr) - - pod_files = get_pod_files(package_variant) - - # copy the necessary files to the staging directory - copy_repo_relative_to_dir( - [license_file, *pod_files["source_files"], *pod_files["test_source_files"], *pod_files["test_resource_files"]], - staging_dir, - ) - - # generate the podspec file from the template - - def path_patterns_as_variable_value(patterns: list[str]): - return ", ".join([f'"{pattern}"' for pattern in patterns]) - - variable_substitutions = { - "C_POD_NAME": c_pod_config["name"], - "DESCRIPTION": pod_config["description"], - "INCLUDE_DIR_LIST": path_patterns_as_variable_value(include_dirs), - "IOS_DEPLOYMENT_TARGET": framework_info["IOS_DEPLOYMENT_TARGET"], - "LICENSE_FILE": license_file, - "NAME": pod_name, - "PUBLIC_HEADER_FILE_LIST": path_patterns_as_variable_value(pod_files["public_header_files"]), - "SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["source_files"]), - "SUMMARY": pod_config["summary"], - "TEST_RESOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_resource_files"]), - "TEST_SOURCE_FILE_LIST": path_patterns_as_variable_value(pod_files["test_source_files"]), - "VERSION": pod_version, - } - - podspec_template = _script_dir / "objc.podspec.template" - podspec = staging_dir / f"{pod_name}.podspec" - - gen_file_from_template(podspec_template, podspec, variable_substitutions) - - return pod_name, podspec - - -def parse_args(): - parser = argparse.ArgumentParser( - description=""" - Assembles the files for the Objective-C pod package in a staging directory. - This directory can be validated (e.g., with `pod lib lint`) and then zipped to create a package for release. - """ - ) - - parser.add_argument( - "--staging-dir", - type=pathlib.Path, - default=pathlib.Path("./onnxruntime-mobile-objc-staging"), - help="Path to the staging directory for the Objective-C pod files.", - ) - parser.add_argument("--pod-version", required=True, help="Objective-C pod version.") - parser.add_argument( - "--framework-info-file", - type=pathlib.Path, - required=True, - help="Path to the framework_info.json file containing additional values for the podspec. " - "This file should be generated by CMake in the build directory.", - ) - parser.add_argument( - "--variant", choices=PackageVariant.release_variant_names(), required=True, help="Pod package variant." - ) - - return parser.parse_args() - - -def main(): - args = parse_args() - - assemble_objc_pod_package( - staging_dir=args.staging_dir, - pod_version=args.pod_version, - framework_info_file=args.framework_info_file, - package_variant=PackageVariant[args.variant], - ) - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py b/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py deleted file mode 100644 index 9713283..0000000 --- a/tools/ci_build/github/scripts/build_and_assemble_ios_pods.py +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import logging -import pathlib -import shutil -import sys -import tempfile - -from assemble_c_pod_package import assemble_c_pod_package -from assemble_objc_pod_package import assemble_objc_pod_package -from package_assembly_utils import PackageVariant, get_ort_version - -SCRIPT_PATH = pathlib.Path(__file__).resolve() -SCRIPT_DIR = SCRIPT_PATH.parent -REPO_DIR = SCRIPT_PATH.parents[4] - - -logging.basicConfig(format="%(asctime)s %(name)s [%(levelname)s] - %(message)s", level=logging.DEBUG) -log = logging.getLogger(SCRIPT_PATH.stem) - - -def parse_args(): - parser = argparse.ArgumentParser( - description="Builds an iOS framework and uses it to assemble iOS pod package files.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - ) - - parser.add_argument( - "--build-dir", - type=pathlib.Path, - default=REPO_DIR / "build" / "ios_framework", - help="The build directory. This will contain the iOS framework build output.", - ) - parser.add_argument( - "--staging-dir", - type=pathlib.Path, - default=REPO_DIR / "build" / "ios_pod_staging", - help="The staging directory. This will contain the iOS pod package files. " - "The pod package files do not have dependencies on files in the build directory.", - ) - - parser.add_argument( - "--pod-version", - default=f"{get_ort_version()}-local", - help="The version string of the pod. The same version is used for all pods.", - ) - - parser.add_argument( - "--variant", - choices=PackageVariant.release_variant_names(), - default=PackageVariant.Mobile.name, - help="Pod package variant.", - ) - - parser.add_argument("--test", action="store_true", help="Run tests on the framework and pod package files.") - - build_framework_group = parser.add_argument_group( - title="iOS framework build arguments", - description="See the corresponding arguments in build_ios_framework.py for details.", - ) - - build_framework_group.add_argument("--include-ops-by-config") - build_framework_group.add_argument( - "--build-settings-file", required=True, help="The positional argument of build_ios_framework.py." - ) - build_framework_group.add_argument( - "-b", - "--build-ios-framework-arg", - action="append", - dest="build_ios_framework_extra_args", - default=[], - help="Pass an argument through to build_ios_framework.py. This may be specified multiple times.", - ) - - args = parser.parse_args() - - return args - - -def run(arg_list, cwd=None): - import os - import shlex - import subprocess - - log.info( - "Running subprocess in '{}'\n {}".format(cwd or os.getcwd(), " ".join([shlex.quote(arg) for arg in arg_list])) - ) - - return subprocess.run(arg_list, check=True, cwd=cwd) - - -def main(): - args = parse_args() - - build_dir = args.build_dir.resolve() - staging_dir = args.staging_dir.resolve() - - # build framework - package_variant = PackageVariant[args.variant] - framework_info_file = build_dir / "framework_info.json" - - log.info("Building iOS framework.") - - build_ios_framework_args = [ - sys.executable, - str(SCRIPT_DIR / "build_ios_framework.py"), - *args.build_ios_framework_extra_args, - ] - - if args.include_ops_by_config is not None: - build_ios_framework_args += ["--include_ops_by_config", args.include_ops_by_config] - - build_ios_framework_args += ["--build_dir", str(build_dir), args.build_settings_file] - - run(build_ios_framework_args) - - if args.test: - test_ios_packages_args = [ - sys.executable, - str(SCRIPT_DIR / "test_ios_packages.py"), - "--fail_if_cocoapods_missing", - "--framework_info_file", - str(framework_info_file), - "--c_framework_dir", - str(build_dir / "framework_out"), - "--variant", - package_variant.name, - ] - - run(test_ios_packages_args) - - # assemble pods and then move them to their target locations (staging_dir/) - staging_dir.mkdir(parents=True, exist_ok=True) - with tempfile.TemporaryDirectory(dir=staging_dir) as pod_assembly_dir_name: - pod_assembly_dir = pathlib.Path(pod_assembly_dir_name) - - log.info("Assembling C/C++ pod.") - - c_pod_staging_dir = pod_assembly_dir / "c_pod" - c_pod_name, c_pod_podspec = assemble_c_pod_package( - staging_dir=c_pod_staging_dir, - pod_version=args.pod_version, - framework_info_file=framework_info_file, - framework_dir=build_dir / "framework_out" / "onnxruntime.xcframework", - public_headers_dir=build_dir / "framework_out" / "Headers", - package_variant=package_variant, - ) - - if args.test: - test_c_pod_args = ["pod", "lib", "lint", "--verbose"] - - run(test_c_pod_args, cwd=c_pod_staging_dir) - - log.info("Assembling Objective-C pod.") - - objc_pod_staging_dir = pod_assembly_dir / "objc_pod" - objc_pod_name, objc_pod_podspec = assemble_objc_pod_package( - staging_dir=objc_pod_staging_dir, - pod_version=args.pod_version, - framework_info_file=framework_info_file, - package_variant=package_variant, - ) - - if args.test: - test_objc_pod_args = ["pod", "lib", "lint", "--verbose", f"--include-podspecs={c_pod_podspec}"] - - run(test_objc_pod_args, cwd=objc_pod_staging_dir) - - def move_dir(src, dst): - if dst.is_dir(): - shutil.rmtree(dst) - shutil.move(src, dst) - - move_dir(c_pod_staging_dir, staging_dir / c_pod_name) - move_dir(objc_pod_staging_dir, staging_dir / objc_pod_name) - - log.info(f"Successfully assembled iOS pods at '{staging_dir}'.") - - -if __name__ == "__main__": - main() diff --git a/tools/ci_build/github/scripts/install_protobuf.sh b/tools/ci_build/github/scripts/install_protobuf.sh deleted file mode 100644 index b912b8e..0000000 --- a/tools/ci_build/github/scripts/install_protobuf.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -set -e -x - -INSTALL_PREFIX='/usr' -DEP_FILE_PATH='/tmp/scripts/deps.txt' -while getopts "p:d:" parameter_Option -do case "${parameter_Option}" -in -p) INSTALL_PREFIX=${OPTARG};; -d) DEP_FILE_PATH=${OPTARG};; -esac -done - -EXTRA_CMAKE_ARGS="" - -case "$(uname -s)" in - Darwin*) - echo 'Building ONNX Runtime on Mac OS X' - EXTRA_CMAKE_ARGS="-DCMAKE_OSX_ARCHITECTURES=x86_64;arm64" - ;; - Linux*) - # Depending on how the compiler has been configured when it was built, sometimes "gcc -dumpversion" shows the full version. - GCC_VERSION=$(gcc -dumpversion | cut -d . -f 1) - #-fstack-clash-protection prevents attacks based on an overlapping heap and stack. - if [ "$GCC_VERSION" -ge 8 ]; then - CFLAGS="$CFLAGS -fstack-clash-protection" - CXXFLAGS="$CXXFLAGS -fstack-clash-protection" - fi - ARCH=$(uname -m) - - if [ "$ARCH" == "x86_64" ] && [ "$GCC_VERSION" -ge 9 ]; then - CFLAGS="$CFLAGS -fcf-protection" - CXXFLAGS="$CXXFLAGS -fcf-protection" - fi - export CFLAGS - export CXXFLAGS - ;; - *) - exit 1 -esac -mkdir -p $INSTALL_PREFIX -echo "Installing protobuf ..." -protobuf_url=$(grep '^protobuf' $DEP_FILE_PATH | cut -d ';' -f 2 ) -if [[ "$protobuf_url" = https* ]]; then - protobuf_url=$(echo $protobuf_url | sed 's/\.zip$/\.tar.gz/') - curl -sSL --retry 5 --retry-delay 10 --create-dirs --fail -L -o protobuf_src.tar.gz $protobuf_url - mkdir protobuf - cd protobuf - tar -zxf ../protobuf_src.tar.gz --strip=1 -else - cp $protobuf_url protobuf_src.zip - unzip protobuf_src.zip - cd protobuf-* -fi - -cmake . -DCMAKE_INSTALL_PREFIX=$INSTALL_PREFIX -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release -Dprotobuf_WITH_ZLIB_DEFAULT=OFF -Dprotobuf_BUILD_SHARED_LIBS=OFF $EXTRA_CMAKE_ARGS -make -j$(getconf _NPROCESSORS_ONLN) -make install -cd .. \ No newline at end of file diff --git a/tools/ci_build/github/scripts/package_assembly_utils.py b/tools/ci_build/github/scripts/package_assembly_utils.py deleted file mode 100644 index e594077..0000000 --- a/tools/ci_build/github/scripts/package_assembly_utils.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import enum -import json -import os -import pathlib -import re -import shutil -from typing import Dict, List - -_script_dir = pathlib.Path(__file__).parent.resolve(strict=True) -repo_root = _script_dir.parents[3] - - -class PackageVariant(enum.Enum): - Full = 0 # full ORT build with all opsets, ops, and types - Mobile = 1 # minimal ORT build with reduced ops - Training = 2 # full ORT build with all opsets, ops, and types, plus training APIs - Test = -1 # for testing purposes only - - @classmethod - def release_variant_names(cls): - return [v.name for v in cls if v.value >= 0] - - @classmethod - def all_variant_names(cls): - return [v.name for v in cls] - - -_template_variable_pattern = re.compile(r"@(\w+)@") # match "@var@" - - -def gen_file_from_template( - template_file: pathlib.Path, output_file: pathlib.Path, variable_substitutions: Dict[str, str], strict: bool = True -): - """ - Generates a file from a template file. - The template file may contain template variables that will be substituted - with the provided values in the generated output file. - In the template file, template variable names are delimited by "@"'s, - e.g., "@var@". - - :param template_file The template file path. - :param output_file The generated output file path. - :param variable_substitutions The mapping from template variable name to value. - :param strict Whether to require the set of template variable names in the file and the keys of - `variable_substitutions` to be equal. - """ - with open(template_file) as template: - content = template.read() - - variables_in_file = set() - - def replace_template_variable(match): - variable_name = match.group(1) - variables_in_file.add(variable_name) - return variable_substitutions.get(variable_name, match.group(0)) - - content = _template_variable_pattern.sub(replace_template_variable, content) - - if strict and variables_in_file != variable_substitutions.keys(): - variables_in_substitutions = set(variable_substitutions.keys()) - raise ValueError( - f"Template file variables and substitution variables do not match. " - f"Only in template file: {sorted(variables_in_file - variables_in_substitutions)}. " - f"Only in substitutions: {sorted(variables_in_substitutions - variables_in_file)}." - ) - - with open(output_file, mode="w") as output: - output.write(content) - - -def filter_files(all_file_patterns: List[str], excluded_file_patterns: List[str]): - """ - Filters file paths based on inclusion and exclusion patterns - - :param all_file_patterns The list of file paths to filter. - :param excluded_file_patterns The list of exclusion patterns. - - :return The filtered list of file paths - """ - # get all files matching the patterns in all_file_patterns - all_files = [str(path.relative_to(repo_root)) for pattern in all_file_patterns for path in repo_root.glob(pattern)] - - # get all files matching the patterns in excluded_file_patterns - exclude_files = [ - str(path.relative_to(repo_root)) for pattern in excluded_file_patterns for path in repo_root.glob(pattern) - ] - - # return the difference - return list(set(all_files) - set(exclude_files)) - - -def copy_repo_relative_to_dir(patterns: List[str], dest_dir: pathlib.Path): - """ - Copies file paths relative to the repo root to a directory. - The given paths or path patterns are relative to the repo root, and the - repo root-relative intermediate directory structure is maintained. - - :param patterns The paths or path patterns relative to the repo root. - :param dest_dir The destination directory. - """ - paths = [path for pattern in patterns for path in repo_root.glob(pattern)] - for path in paths: - repo_relative_path = path.relative_to(repo_root) - dst_path = dest_dir / repo_relative_path - os.makedirs(dst_path.parent, exist_ok=True) - shutil.copy(path, dst_path) - - -def load_json_config(json_config_file: pathlib.Path): - """ - Loads configuration info from a JSON file. - - :param json_config_file The JSON configuration file path. - :return The configuration info values. - """ - with open(json_config_file) as config: - return json.load(config) - - -def get_ort_version(): - """ - Gets the ONNX Runtime version string from the repo. - - :return The ONNX Runtime version string. - """ - with open(repo_root / "VERSION_NUMBER") as version_file: - return version_file.read().strip() diff --git a/tools/ci_build/github/scripts/test_ios_packages.py b/tools/ci_build/github/scripts/test_ios_packages.py deleted file mode 100644 index e53a884..0000000 --- a/tools/ci_build/github/scripts/test_ios_packages.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import argparse -import contextlib -import os -import pathlib -import shutil -import subprocess -import tempfile - -from assemble_c_pod_package import assemble_c_pod_package -from package_assembly_utils import PackageVariant, gen_file_from_template, get_ort_version - -SCRIPT_PATH = pathlib.Path(__file__).resolve(strict=True) -REPO_DIR = SCRIPT_PATH.parents[4] - - -def _test_ios_packages(args): - # check if CocoaPods is installed - if shutil.which("pod") is None: - if args.fail_if_cocoapods_missing: - raise ValueError("CocoaPods is required for this test") - else: - print("CocoaPods is not installed, ignore this test") - return - - # Now we need to create a zip file contains the framework and the podspec file, both of these 2 files - # should be under the c_framework_dir - c_framework_dir = args.c_framework_dir.resolve() - if not c_framework_dir.is_dir(): - raise FileNotFoundError(f"c_framework_dir {c_framework_dir} is not a folder.") - - has_framework = (c_framework_dir / "onnxruntime.framework").exists() - has_xcframework = (c_framework_dir / "onnxruntime.xcframework").exists() - - if not has_framework and not has_xcframework: - raise FileNotFoundError(f"{c_framework_dir} does not have onnxruntime.framework/xcframework") - - if has_framework and has_xcframework: - raise ValueError("Cannot proceed when both onnxruntime.framework and onnxruntime.xcframework exist") - - framework_name = "onnxruntime.framework" if has_framework else "onnxruntime.xcframework" - - # create a temp folder - - with contextlib.ExitStack() as context_stack: - if args.test_project_stage_dir is None: - stage_dir = pathlib.Path(context_stack.enter_context(tempfile.TemporaryDirectory())).resolve() - else: - # If we specify the stage dir, then use it to create test project - stage_dir = args.test_project_stage_dir.resolve() - if os.path.exists(stage_dir): - shutil.rmtree(stage_dir) - os.makedirs(stage_dir) - - # assemble the test project here - target_proj_path = stage_dir / "ios_package_test" - - # copy the test project source files to target_proj_path - test_proj_path = pathlib.Path(REPO_DIR, "onnxruntime/test/platform/ios/ios_package_test") - shutil.copytree(test_proj_path, target_proj_path) - - # assemble local pod files here - local_pods_dir = stage_dir / "local_pods" - - # We will only publish xcframework, however, assembly of the xcframework is a post process - # and it cannot be done by CMake for now. See, https://gitlab.kitware.com/cmake/cmake/-/issues/21752 - # For a single sysroot and arch built by build.py or cmake, we can only generate framework - # We still need a way to test it. framework_dir and public_headers_dir have different values when testing a - # framework and a xcframework. - framework_dir = args.c_framework_dir / framework_name - public_headers_dir = framework_dir / "Headers" if has_framework else args.c_framework_dir / "Headers" - - pod_name, podspec = assemble_c_pod_package( - staging_dir=local_pods_dir, - pod_version=get_ort_version(), - framework_info_file=args.framework_info_file, - public_headers_dir=public_headers_dir, - framework_dir=framework_dir, - package_variant=PackageVariant[args.variant], - ) - - # move podspec out to target_proj_path first - podspec = shutil.move(podspec, target_proj_path / podspec.name) - - # create a zip file contains the framework - zip_file_path = local_pods_dir / f"{pod_name}.zip" - # shutil.make_archive require target file as full path without extension - shutil.make_archive(zip_file_path.with_suffix(""), "zip", root_dir=local_pods_dir) - - # update the podspec to point to the local framework zip file - with open(podspec) as file: - file_data = file.read() - - file_data = file_data.replace("file:///http_source_placeholder", f"file:///{zip_file_path}") - - with open(podspec, "w") as file: - file.write(file_data) - - # generate Podfile to point to pod - gen_file_from_template( - target_proj_path / "Podfile.template", - target_proj_path / "Podfile", - {"C_POD_NAME": pod_name, "C_POD_PODSPEC": f"./{podspec.name}"}, - ) - - # clean the Cocoapods cache first, in case the same pod was cached in previous runs - subprocess.run(["pod", "cache", "clean", "--all"], shell=False, check=True, cwd=target_proj_path) - - # install pods - subprocess.run(["pod", "install"], shell=False, check=True, cwd=target_proj_path) - - # run the tests - if not args.prepare_test_project_only: - simulator_device_name = subprocess.check_output( - ["bash", str(REPO_DIR / "tools" / "ci_build" / "github" / "apple" / "get_simulator_device_name.sh")], - text=True, - ).strip() - - subprocess.run( - [ - "xcrun", - "xcodebuild", - "test", - "-workspace", - "./ios_package_test.xcworkspace", - "-scheme", - "ios_package_test", - "-destination", - f"platform=iOS Simulator,OS=latest,name={simulator_device_name}", - ], - shell=False, - check=True, - cwd=target_proj_path, - ) - - -def parse_args(): - parser = argparse.ArgumentParser( - os.path.basename(__file__), description="Test iOS framework using CocoaPods package." - ) - - parser.add_argument( - "--fail_if_cocoapods_missing", - action="store_true", - help="This script will fail if CocoaPods is not installed, " - "will not throw error unless fail_if_cocoapod_missing is set.", - ) - - parser.add_argument( - "--framework_info_file", - type=pathlib.Path, - required=True, - help="Path to the framework_info.json file containing additional values for the podspec. " - "This file should be generated by CMake in the build directory.", - ) - - parser.add_argument( - "--c_framework_dir", type=pathlib.Path, required=True, help="Provide the parent directory for C/C++ framework" - ) - - parser.add_argument( - "--variant", - choices=PackageVariant.all_variant_names(), - default=PackageVariant.Test.name, - help="Pod package variant.", - ) - - parser.add_argument( - "--test_project_stage_dir", - type=pathlib.Path, - help="The stage dir for the test project, if not specified, will use a temporary path", - ) - - parser.add_argument( - "--prepare_test_project_only", - action="store_true", - help="Prepare the test project only, without running the tests", - ) - - return parser.parse_args() - - -def main(): - args = parse_args() - _test_ios_packages(args) - - -if __name__ == "__main__": - main() diff --git a/tools/ci_build/github/templates/install-appcenter.yml b/tools/ci_build/github/templates/install-appcenter.yml deleted file mode 100644 index 51be73d..0000000 --- a/tools/ci_build/github/templates/install-appcenter.yml +++ /dev/null @@ -1,12 +0,0 @@ -# Install appcenter CLI - -parameters: -- name: appcenterVersion - type: string - default: "2.13.7" - -steps: -- bash: | - set -e -x - npm install -g appcenter-cli@${{ parameters.appcenterVersion }} - displayName: Install appcenter CLI ${{ parameters.appcenterVersion }} From ed90065a80dee4673bb9bec6558250640c5cb4a9 Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 12:02:56 -0700 Subject: [PATCH 52/70] update version.txt --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index 71bd5d9..d19d089 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.16.0 \ No newline at end of file +1.15.0 \ No newline at end of file From 2c68b6f3795eb8971ba9b38ac370d007c21030ef Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 12:07:09 -0700 Subject: [PATCH 53/70] indentation --- .../mac-ios-swift-packaging-pipeline.yml | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index ffe6fbe..89acb8a 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -75,39 +75,39 @@ stages: parameters : condition : 'succeeded' - - stage: SPM iOS release packaging testing - dependsOn: [] - jobs: - - job: SPMIosPackaging - displayName: "SPM iOS Packaging" +- stage: SPM iOS release packaging testing + dependsOn: [] + jobs: + - job: SPMIosPackaging + displayName: "SPM iOS Packaging" - pool: - vmImage: "macOS-13" + pool: + vmImage: "macOS-13" - variables: - xcodeVersion: "14.3" + variables: + xcodeVersion: "14.3" - timeoutInMinutes: 300 + timeoutInMinutes: 300 - steps: - - template: templates/use-xcode-version.yml - parameters: - xcodeVersion: ${{ variables.xcodeVersion }} + steps: + - template: templates/use-xcode-version.yml + parameters: + xcodeVersion: ${{ variables.xcodeVersion }} - - script: | - set -e -x - VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - SPM_POD_VERSION="$(cat "${VERSION_FILE}")" - shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Print ORT iOS Release Pod checksum" + - script: | + set -e -x + VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + SPM_POD_VERSION="$(cat "${VERSION_FILE}")" + shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + workingDirectory: "$(Build.SourcesDirectory)" + displayName: "Print ORT iOS Release Pod checksum" - - script: | - set -e -x - xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Test Package.swift usage" + - 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' + - template: templates/component-governance-component-detection-steps.yml + parameters : + condition : 'succeeded' \ No newline at end of file From 6ea8518d8bf5d2e12a881015065ffda74387f245 Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 12:10:30 -0700 Subject: [PATCH 54/70] naming --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 89acb8a..9e7ffc9 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -11,11 +11,11 @@ parameters: name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format stages: -- stage: SPM iOS local packaging testing +- stage: SPM_IOS_Local_Packaging_Testing dependsOn: [] jobs: - job: SPMIosPackaging - displayName: "SPM iOS Packaging" + displayName: "SPM iOS Packaging Local" pool: vmImage: "macOS-13" @@ -75,11 +75,11 @@ stages: parameters : condition : 'succeeded' -- stage: SPM iOS release packaging testing +- stage: SPM_IOS_Release_Packaging_Testing dependsOn: [] jobs: - job: SPMIosPackaging - displayName: "SPM iOS Packaging" + displayName: "SPM iOS Packaging Release" pool: vmImage: "macOS-13" From 5cb8d2277141815c31f27752bf475449b390d741 Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 12:20:14 -0700 Subject: [PATCH 55/70] update --- .../ci_build/github/mac-ios-swift-packaging-pipeline.yml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 9e7ffc9..ec430f7 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -94,14 +94,6 @@ stages: parameters: xcodeVersion: ${{ variables.xcodeVersion }} - - script: | - set -e -x - VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - SPM_POD_VERSION="$(cat "${VERSION_FILE}")" - shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Print ORT iOS Release Pod checksum" - - script: | set -e -x xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' From 21422d0f9bb8fda3dfa5c117f82229a7a26478dd Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 13:38:18 -0700 Subject: [PATCH 56/70] try latest option --- .../github/mac-ios-swift-packaging-pipeline.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index ec430f7..c0c051b 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -38,7 +38,7 @@ stages: buildType: 'specific' project: 'Lotus' definition: 995 - buildVersionToDownload: 'latestFromBranch' + buildVersionToDownload: 'latest' branchName: 'rel-1.15.0' targetPath: '$(Build.ArtifactStagingDirectory)' @@ -94,6 +94,14 @@ stages: parameters: xcodeVersion: ${{ variables.xcodeVersion }} + # - script: | + # set -e -x + # VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + # SPM_POD_VERSION="$(cat "${VERSION_FILE}")" + # shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + # workingDirectory: "$(Build.SourcesDirectory)" + # displayName: "Print ORT iOS Release Pod checksum" + - script: | set -e -x xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' From 89e64e07ed0a1890d4cdbd7ee8948be8929fb15a Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 13:57:46 -0700 Subject: [PATCH 57/70] fix --- tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index c0c051b..1633a97 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -22,7 +22,7 @@ stages: variables: xcodeVersion: "14.3" - artifactsNamne: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main + artifactsName: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main timeoutInMinutes: 300 From 6dcdf0b6b47c5bf1cbc871820248aa58e0a461e6 Mon Sep 17 00:00:00 2001 From: rachguo Date: Fri, 14 Jul 2023 14:10:13 -0700 Subject: [PATCH 58/70] fix typo and update --- .../mac-ios-swift-packaging-pipeline.yml | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml index 1633a97..bd8ca8e 100644 --- a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml +++ b/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml @@ -65,9 +65,9 @@ stages: xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' rm swift/pod-archive-onnxruntime-c-*.zip workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Print ORT iOS Pod checksum and test Package.swift usage" + displayName: "Print ORT iOS Pod checksum and Test Package.swift usage" - - publish: "$(Build.ArtifactStagingDirectory)/$(artifactName)" + - publish: "$(Build.ArtifactStagingDirectory)/$(artifactsName)" artifact: ios_packaging_artifacts displayName: "Publish artifacts" @@ -94,13 +94,17 @@ stages: parameters: xcodeVersion: ${{ variables.xcodeVersion }} - # - script: | - # set -e -x - # VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - # SPM_POD_VERSION="$(cat "${VERSION_FILE}")" - # shasum -a 256 "https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - # workingDirectory: "$(Build.SourcesDirectory)" - # displayName: "Print ORT iOS Release Pod checksum" + - script: | + set -e -x + VERSION_FILE="$(Build.SourcesDirectory)/version.txt" + SPM_POD_VERSION="$(cat "${VERSION_FILE}")" + + POD_ARCHIVE_URL="https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + + curl -o pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip ${POD_ARCHIVE_URL} + shasum -a 256 "pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" + workingDirectory: "$(Build.SourcesDirectory)" + displayName: "Print ORT iOS Release Pod checksum" - script: | set -e -x From ff358ee37a59c9180ab76e2cbef1724baabe2b7b Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 19 Jul 2023 13:48:48 -0700 Subject: [PATCH 59/70] update Package.swift and move pipelines --- .../mac-ios-swift-packaging-pipeline.yml | 0 ...ponent-governance-component-detection-steps.yml | 0 .../templates/use-xcode-version.yml | 0 Package.swift | 14 ++++++-------- 4 files changed, 6 insertions(+), 8 deletions(-) rename {tools/ci_build/github => .pipelines}/mac-ios-swift-packaging-pipeline.yml (100%) rename {tools/ci_build/github => .pipelines}/templates/component-governance-component-detection-steps.yml (100%) rename {tools/ci_build/github => .pipelines}/templates/use-xcode-version.yml (100%) diff --git a/tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml b/.pipelines/mac-ios-swift-packaging-pipeline.yml similarity index 100% rename from tools/ci_build/github/mac-ios-swift-packaging-pipeline.yml rename to .pipelines/mac-ios-swift-packaging-pipeline.yml diff --git a/tools/ci_build/github/templates/component-governance-component-detection-steps.yml b/.pipelines/templates/component-governance-component-detection-steps.yml similarity index 100% rename from tools/ci_build/github/templates/component-governance-component-detection-steps.yml rename to .pipelines/templates/component-governance-component-detection-steps.yml diff --git a/tools/ci_build/github/templates/use-xcode-version.yml b/.pipelines/templates/use-xcode-version.yml similarity index 100% rename from tools/ci_build/github/templates/use-xcode-version.yml rename to .pipelines/templates/use-xcode-version.yml diff --git a/Package.swift b/Package.swift index 54609b1..167051f 100644 --- a/Package.swift +++ b/Package.swift @@ -9,12 +9,11 @@ // For context, the end user's config will look something like: // // dependencies: [ -// .package(url: "https://github.com/microsoft/onnxruntime", branch: "rel-1.15.0"), +// #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"), // ... // ], // -// NOTE: The direct consumption creates a somewhat complicated setup to 'release' a new version of the ORT SPM package. -// TBD: how to manage the release process import PackageDescription import class Foundation.ProcessInfo @@ -54,12 +53,11 @@ let package = Package( // // There are 2 scenarios: // -// Release branch of ORT github repo: -// Target will be set to the released pod archive and its checksum. +// Release version of ORT SPM github repo: +// Target will be set to the latest released ORT iOS pod archive and its checksum. // -// Any other branch/tag of ORT github repo: -// Invalid by default. We do not have a pod archive that is guaranteed to work -// as the objective-c bindings may have changed since the pod archive was released. +// 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. From c07d49294bf4073dc7302642b9342b3a8e61a19d Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 19 Jul 2023 14:27:05 -0700 Subject: [PATCH 60/70] address pr comments --- ...line.yml => mac-ios-swift-ci-pipeline.yml} | 47 ++++--------------- ...t-governance-component-detection-steps.yml | 4 -- README.md | 4 +- 3 files changed, 12 insertions(+), 43 deletions(-) rename .pipelines/{mac-ios-swift-packaging-pipeline.yml => mac-ios-swift-ci-pipeline.yml} (67%) diff --git a/.pipelines/mac-ios-swift-packaging-pipeline.yml b/.pipelines/mac-ios-swift-ci-pipeline.yml similarity index 67% rename from .pipelines/mac-ios-swift-packaging-pipeline.yml rename to .pipelines/mac-ios-swift-ci-pipeline.yml index bd8ca8e..516623f 100644 --- a/.pipelines/mac-ios-swift-packaging-pipeline.yml +++ b/.pipelines/mac-ios-swift-ci-pipeline.yml @@ -1,21 +1,9 @@ -parameters: -- name: BuildType - displayName: |- - Type of build. - "normal": A normal build not for publication. - type: string #TODO: add other build types here - values: - - normal - default: normal - -name: "$(Date:yyyyMMdd)$(Rev:rrr)" # build number format - stages: -- stage: SPM_IOS_Local_Packaging_Testing +- stage: SPM_IOS_Local_Pod_Testing dependsOn: [] jobs: - - job: SPMIosPackaging - displayName: "SPM iOS Packaging Local" + - job: j + displayName: "Test with latest local ORT native pod" pool: vmImage: "macOS-13" @@ -24,7 +12,7 @@ stages: xcodeVersion: "14.3" artifactsName: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main - timeoutInMinutes: 300 + timeoutInMinutes: 60 steps: - template: templates/use-xcode-version.yml @@ -33,11 +21,12 @@ stages: # 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 + definition: 995 #'definitionid' is obtained from `System.DefinitionId` of ORT CI: onnxruntime-ios-packaging-pipeline buildVersionToDownload: 'latest' branchName: 'rel-1.15.0' targetPath: '$(Build.ArtifactStagingDirectory)' @@ -67,19 +56,15 @@ stages: workingDirectory: "$(Build.SourcesDirectory)" displayName: "Print ORT iOS Pod checksum and Test Package.swift usage" - - publish: "$(Build.ArtifactStagingDirectory)/$(artifactsName)" - artifact: ios_packaging_artifacts - displayName: "Publish artifacts" - - template: templates/component-governance-component-detection-steps.yml parameters : condition : 'succeeded' -- stage: SPM_IOS_Release_Packaging_Testing +- stage: SPM_IOS_Release_Pod_Testing dependsOn: [] jobs: - - job: SPMIosPackaging - displayName: "SPM iOS Packaging Release" + - job: j + displayName: "Test with released ORT native pod" pool: vmImage: "macOS-13" @@ -87,25 +72,13 @@ stages: variables: xcodeVersion: "14.3" - timeoutInMinutes: 300 + timeoutInMinutes: 60 steps: - template: templates/use-xcode-version.yml parameters: xcodeVersion: ${{ variables.xcodeVersion }} - - script: | - set -e -x - VERSION_FILE="$(Build.SourcesDirectory)/version.txt" - SPM_POD_VERSION="$(cat "${VERSION_FILE}")" - - POD_ARCHIVE_URL="https://onnxruntimepackages.z14.web.core.windows.net/pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - - curl -o pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip ${POD_ARCHIVE_URL} - shasum -a 256 "pod-archive-onnxruntime-c-${SPM_POD_VERSION}.zip" - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Print ORT iOS Release Pod checksum" - - script: | set -e -x xcodebuild test -scheme onnxruntime -destination 'platform=iOS Simulator,name=iPhone 14' diff --git a/.pipelines/templates/component-governance-component-detection-steps.yml b/.pipelines/templates/component-governance-component-detection-steps.yml index daea499..fb503bc 100644 --- a/.pipelines/templates/component-governance-component-detection-steps.yml +++ b/.pipelines/templates/component-governance-component-detection-steps.yml @@ -12,7 +12,3 @@ steps: 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())) - inputs: - # ignore dmlc-core tracker for its CI, which is not used in onnxruntime build - # ignore unit tests in emscripten. emscripten unit tests are not used in onnxruntime build - ignoreDirectories: '$(Build.SourcesDirectory)/cmake/external/emsdk/upstream/emscripten/tests' diff --git a/README.md b/README.md index 24d1a87..85af6ad 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# ONNXRuntime Swift Package Manager +# Swift Package Manager for ONNX Runtime -A light-weight [ONNXRuntime](https://github.com/microsoft/onnxruntime) repository for hosting [Swift Package Manager(SPM)](https://www.swift.org/package-manager/) support. +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. SPM is the alternative to CocoaPods when desired platform to consume is mobile iOS. From 071c82ffd78def753e4b6ea9e72d8367bdb930fe Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 19 Jul 2023 15:07:53 -0700 Subject: [PATCH 61/70] remove not required files --- Package.swift | 2 +- objectivec/assert_arc_enabled.mm | 4 - objectivec/docs/jazzy_config.yaml | 13 - objectivec/docs/main_page.md | 5 - objectivec/docs/readme.md | 17 - objectivec/error_utils.mm | 29 -- objectivec/ort_coreml_execution_provider.mm | 44 --- objectivec/ort_enums.mm | 133 ------- objectivec/ort_env.mm | 44 --- objectivec/ort_session.mm | 361 ------------------ objectivec/ort_value.mm | 160 -------- objectivec/ort_xnnpack_execution_provider.mm | 31 -- objectivec/test/assert_arc_enabled.mm | 4 - objectivec/test/assertion_utils.h | 32 -- objectivec/test/ort_env_test.mm | 30 -- objectivec/test/ort_session_test.mm | 243 ------------ objectivec/test/ort_value_test.mm | 79 ---- objectivec/test/testdata/gen_models.sh | 12 - objectivec/test/testdata/single_add.basic.ort | Bin 1296 -> 0 bytes objectivec/test/testdata/single_add.onnx | Bin 93 -> 0 bytes objectivec/test/testdata/single_add_gen.py | 19 - 21 files changed, 1 insertion(+), 1261 deletions(-) delete mode 100644 objectivec/assert_arc_enabled.mm delete mode 100644 objectivec/docs/jazzy_config.yaml delete mode 100644 objectivec/docs/main_page.md delete mode 100644 objectivec/docs/readme.md delete mode 100644 objectivec/error_utils.mm delete mode 100644 objectivec/ort_coreml_execution_provider.mm delete mode 100644 objectivec/ort_enums.mm delete mode 100644 objectivec/ort_env.mm delete mode 100644 objectivec/ort_session.mm delete mode 100644 objectivec/ort_value.mm delete mode 100644 objectivec/ort_xnnpack_execution_provider.mm delete mode 100644 objectivec/test/assert_arc_enabled.mm delete mode 100644 objectivec/test/assertion_utils.h delete mode 100644 objectivec/test/ort_env_test.mm delete mode 100644 objectivec/test/ort_session_test.mm delete mode 100644 objectivec/test/ort_value_test.mm delete mode 100755 objectivec/test/testdata/gen_models.sh delete mode 100644 objectivec/test/testdata/single_add.basic.ort delete mode 100644 objectivec/test/testdata/single_add.onnx delete mode 100644 objectivec/test/testdata/single_add_gen.py diff --git a/Package.swift b/Package.swift index 167051f..6d09521 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - exclude: ["test", "docs", "ReadMe.md", "format_objc.sh"], + exclude: ["ReadMe.md", "format_objc.sh"], cxxSettings: [ .define("SPM_BUILD"), .unsafeFlags(["-std=c++17", diff --git a/objectivec/assert_arc_enabled.mm b/objectivec/assert_arc_enabled.mm deleted file mode 100644 index 9aa0bad..0000000 --- a/objectivec/assert_arc_enabled.mm +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled."); diff --git a/objectivec/docs/jazzy_config.yaml b/objectivec/docs/jazzy_config.yaml deleted file mode 100644 index 676f89d..0000000 --- a/objectivec/docs/jazzy_config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -module: ONNX Runtime Objective-C API -author: ONNX Runtime Authors -author_url: https://www.onnxruntime.ai -github_url: https://github.com/microsoft/onnxruntime - -objc: true -umbrella_header: ../include/onnxruntime.h -framework_root: .. - -readme: ./main_page.md - -hide_documentation_coverage: true -undocumented_text: "" diff --git a/objectivec/docs/main_page.md b/objectivec/docs/main_page.md deleted file mode 100644 index fdc7c80..0000000 --- a/objectivec/docs/main_page.md +++ /dev/null @@ -1,5 +0,0 @@ -# ONNX Runtime Objective-C API - -ONNX Runtime provides an Objective-C API. - -It can be used from Objective-C/C++ or Swift with a bridging header. diff --git a/objectivec/docs/readme.md b/objectivec/docs/readme.md deleted file mode 100644 index 5697480..0000000 --- a/objectivec/docs/readme.md +++ /dev/null @@ -1,17 +0,0 @@ -# Objective-C API Documentation - -The API should be documented with comments in the [public header files](../include). - -## Documentation Generation - -The [Jazzy](https://github.com/realm/jazzy) tool is used to generate documentation from the code. - -To generate documentation, from the repo root, run: - -```bash -jazzy --config objectivec/docs/jazzy_config.yaml --output -``` - -The generated documentation website files will be in ``. - -[main_page.md](./main_page.md) contains content for the main page of the generated documentation website. diff --git a/objectivec/error_utils.mm b/objectivec/error_utils.mm deleted file mode 100644 index 9186326..0000000 --- a/objectivec/error_utils.mm +++ /dev/null @@ -1,29 +0,0 @@ -// 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 diff --git a/objectivec/ort_coreml_execution_provider.mm b/objectivec/ort_coreml_execution_provider.mm deleted file mode 100644 index 6340fde..0000000 --- a/objectivec/ort_coreml_execution_provider.mm +++ /dev/null @@ -1,44 +0,0 @@ -// 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(options); - ORTSaveCodeAndDescriptionToError(ORT_FAIL, "CoreML execution provider is not enabled.", error); - return NO; -#endif -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_enums.mm b/objectivec/ort_enums.mm deleted file mode 100644 index 0144a33..0000000 --- a/objectivec/ort_enums.mm +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_enums_internal.h" - -#include - -#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 -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"); -} diff --git a/objectivec/ort_env.mm b/objectivec/ort_env.mm deleted file mode 100644 index cd83ac5..0000000 --- a/objectivec/ort_env.mm +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_env_internal.h" - -#include - -#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 _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 diff --git a/objectivec/ort_session.mm b/objectivec/ort_session.mm deleted file mode 100644 index c4f57b0..0000000 --- a/objectivec/ort_session.mm +++ /dev/null @@ -1,361 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_session_internal.h" - -#include -#include - -#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 _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*)inputs - outputs:(NSDictionary*)outputs - runOptions:(nullable ORTRunOptions*)runOptions - error:(NSError**)error { - try { - if (!runOptions) { - runOptions = [[ORTRunOptions alloc] initWithError:error]; - if (!runOptions) { - return NO; - } - } - - std::vector inputNames, outputNames; - std::vector inputValues; - std::vector outputValues; - - for (NSString* inputName in inputs) { - inputNames.push_back(inputName.UTF8String); - inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); - } - - for (NSString* outputName in outputs) { - outputNames.push_back(outputName.UTF8String); - outputValues.push_back(static_cast([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*)runWithInputs:(NSDictionary*)inputs - outputNames:(NSSet*)outputNameSet - runOptions:(nullable ORTRunOptions*)runOptions - error:(NSError**)error { - try { - if (!runOptions) { - runOptions = [[ORTRunOptions alloc] initWithError:error]; - if (!runOptions) { - return nil; - } - } - - NSArray* outputNameArray = outputNameSet.allObjects; - - std::vector inputNames, outputNames; - std::vector inputValues; - std::vector outputValues; - - for (NSString* inputName in inputs) { - inputNames.push_back(inputName.UTF8String); - inputValues.push_back(static_cast([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* 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*)inputNamesWithError:(NSError**)error { - return [self namesWithType:NamedValueType::Input error:error]; -} - -- (nullable NSArray*)overridableInitializerNamesWithError:(NSError**)error { - return [self namesWithType:NamedValueType::OverridableInitializer error:error]; -} - -- (nullable NSArray*)outputNamesWithError:(NSError**)error { - return [self namesWithType:NamedValueType::Output error:error]; -} - -#pragma mark - Private - -- (nullable NSArray*)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* 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 _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*)providerOptions - error:(NSError**)error { - try { - std::unordered_map 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 _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 diff --git a/objectivec/ort_value.mm b/objectivec/ort_value.mm deleted file mode 100644 index ce77ca7..0000000 --- a/objectivec/ort_value.mm +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import "ort_value_internal.h" - -#include - -#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 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 _value; - std::optional _typeInfo; -} - -#pragma mark - Public - -- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData - elementType:(ORTTensorElementDataType)elementType - shape:(NSArray*)shape - error:(NSError**)error { - try { - const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); - const auto ONNXElementType = PublicToCAPITensorElementType(elementType); - const auto shapeVector = [shape]() { - std::vector 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 diff --git a/objectivec/ort_xnnpack_execution_provider.mm b/objectivec/ort_xnnpack_execution_provider.mm deleted file mode 100644 index 324974a..0000000 --- a/objectivec/ort_xnnpack_execution_provider.mm +++ /dev/null @@ -1,31 +0,0 @@ -// 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 diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm deleted file mode 100644 index 9aa0bad..0000000 --- a/objectivec/test/assert_arc_enabled.mm +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h deleted file mode 100644 index f2b73e6..0000000 --- a/objectivec/test/assertion_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -NS_ASSUME_NONNULL_BEGIN - -#define ORTAssertNullableResultSuccessful(result, error) \ - do { \ - XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertBoolResultSuccessful(result, error) \ - do { \ - XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertNullableResultUnsuccessful(result, error) \ - do { \ - XCTAssertNil(result); \ - XCTAssertNotNil(error); \ - } while (0) - -#define ORTAssertBoolResultUnsuccessful(result, error) \ - do { \ - XCTAssertFalse(result); \ - XCTAssertNotNil(error); \ - } while (0) - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm deleted file mode 100644 index 420f55f..0000000 --- a/objectivec/test/ort_env_test.mm +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_env.h" - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTEnvTest : XCTestCase -@end - -@implementation ORTEnvTest -- (void)testGetOrtVersion { - NSString* ver = ORTVersion(); - XCTAssertNotNil(ver); -} - -- (void)testInitOk { - NSError* err = nil; - ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(env, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm deleted file mode 100644 index 790ad1c..0000000 --- a/objectivec/test/ort_session_test.mm +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_coreml_execution_provider.h" -#import "ort_xnnpack_execution_provider.h" -#import "ort_env.h" -#import "ort_session.h" -#import "ort_value.h" - -#import "test/assertion_utils.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTSessionTest : XCTestCase - -@property(readonly, nullable) ORTEnv* ortEnv; - -@end - -@implementation ORTSessionTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - - NSError* err = nil; - _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(_ortEnv, err); -} - -- (void)tearDown { - _ortEnv = nil; - - [super tearDown]; -} - -// model with an Add op -// inputs: A, B -// output: C = A + B -+ (NSString*)getAddModelPath { - NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; - NSString* path = [bundle pathForResource:@"single_add.basic" - ofType:@"ort"]; - return path; -} - -+ (NSMutableData*)dataWithScalarFloat:(float)value { - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; - return data; -} - -+ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { - NSArray* shape = @[ @1 ]; - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeFloat - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - return ortValue; -} - -+ (ORTSessionOptions*)makeSessionOptions { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(sessionOptions, err); - return sessionOptions; -} - -+ (ORTRunOptions*)makeRunOptions { - NSError* err = nil; - ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(runOptions, err); - return runOptions; -} - -- (void)testInitAndRunWithPreallocatedOutputOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultSuccessful(runResult, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testInitAndRunOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSDictionary* outputs = - [session runWithInputs:@{@"A" : a, @"B" : b} - outputNames:[NSSet setWithArray:@[ @"C" ]] - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertNullableResultSuccessful(outputs, err); - - ORTValue* cOutput = outputs[@"C"]; - XCTAssertNotNil(cOutput); - - NSData* cData = [cOutput tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(cData, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testGetNamesOk { - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSArray* inputNames = [session inputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(inputNames, err); - XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); - - NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; - ORTAssertNullableResultSuccessful(overridableInitializerNames, err); - XCTAssertEqualObjects(overridableInitializerNames, (@[])); - - NSArray* outputNames = [session outputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(outputNames, err); - XCTAssertEqualObjects(outputNames, (@[ @"C" ])); -} - -- (void)testInitFailsWithInvalidPath { - NSString* invalidModelPath = @"invalid/path/to/model.ort"; - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:invalidModelPath - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultUnsuccessful(session, err); -} - -- (void)testRunFailsWithInvalidInput { - NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"D" : d} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultUnsuccessful(runResult, err); -} - -- (void)testAppendCoreMLEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; - coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option - - BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions - error:&err]; - - if (!ORTIsCoreMLExecutionProviderAvailable()) { - ORTAssertBoolResultUnsuccessful(appendResult, err); - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} - -- (void)testAppendXnnpackEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; - XnnpackOptions.intra_op_num_threads = 2; - - BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions - error:&err]; - // Without xnnpack EP in building also can pass the test - NSString* err_msg = [err localizedDescription]; - if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm deleted file mode 100644 index 734ad39..0000000 --- a/objectivec/test/ort_value_test.mm +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_value.h" - -#include - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTValueTest : XCTestCase -@end - -@implementation ORTValueTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)testInitTensorOk { - int32_t value = 42; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value - length:sizeof(int32_t)]; - NSArray* shape = @[ @1 ]; - - const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:elementType - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - - auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { - XCTAssertEqual(tensorInfo.elementType, elementType); - XCTAssertEqualObjects(tensorInfo.shape, shape); - }; - - ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(typeInfo, err); - XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); - XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); - checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); - - ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(tensorInfo, err); - checkTensorInfo(tensorInfo); - - NSData* actualData = [ortValue tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(actualData, err); - XCTAssertEqual(actualData.length, sizeof(int32_t)); - int32_t actualValue; - memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); - XCTAssertEqual(actualValue, value); -} - -- (void)testInitTensorFailsWithDataSmallerThanShape { - std::vector values{1, 2, 3, 4}; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() - length:values.size() * sizeof(int32_t)]; - NSArray* shape = @[ @2, @3 ]; // too large - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeInt32 - shape:shape - error:&err]; - ORTAssertNullableResultUnsuccessful(ortValue, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh deleted file mode 100755 index 0a58ca8..0000000 --- a/objectivec/test/testdata/gen_models.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -# Get directory this script is in -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -cd ${DIR} - -python3 ./single_add_gen.py - -ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort deleted file mode 100644 index f622784b35366ea8f0c33ccbdb513b5d6f7df7c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx deleted file mode 100644 index 82e8fe669e0d84b6111f678b0742a552d820269b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py deleted file mode 100644 index 15b4372..0000000 --- a/objectivec/test/testdata/single_add_gen.py +++ /dev/null @@ -1,19 +0,0 @@ -import onnx -from onnx import TensorProto, helper - -graph = helper.make_graph( - [ # nodes - helper.make_node("Add", ["A", "B"], ["C"], "Add"), - ], - "SingleAdd", # name - [ # inputs - helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), - helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), - ], - [ # outputs - helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), - ], -) - -model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) -onnx.save(model, r"single_add.onnx") From f3396b6ce4ec9f760ff24adbfb59f015360a892f Mon Sep 17 00:00:00 2001 From: rachguo Date: Wed, 19 Jul 2023 15:12:23 -0700 Subject: [PATCH 62/70] Revert "remove not required files" This reverts commit 071c82ffd78def753e4b6ea9e72d8367bdb930fe. --- Package.swift | 2 +- objectivec/assert_arc_enabled.mm | 4 + objectivec/docs/jazzy_config.yaml | 13 + objectivec/docs/main_page.md | 5 + objectivec/docs/readme.md | 17 + objectivec/error_utils.mm | 29 ++ objectivec/ort_coreml_execution_provider.mm | 44 +++ objectivec/ort_enums.mm | 133 +++++++ objectivec/ort_env.mm | 44 +++ objectivec/ort_session.mm | 361 ++++++++++++++++++ objectivec/ort_value.mm | 160 ++++++++ objectivec/ort_xnnpack_execution_provider.mm | 31 ++ objectivec/test/assert_arc_enabled.mm | 4 + objectivec/test/assertion_utils.h | 32 ++ objectivec/test/ort_env_test.mm | 30 ++ objectivec/test/ort_session_test.mm | 243 ++++++++++++ objectivec/test/ort_value_test.mm | 79 ++++ objectivec/test/testdata/gen_models.sh | 12 + objectivec/test/testdata/single_add.basic.ort | Bin 0 -> 1296 bytes objectivec/test/testdata/single_add.onnx | Bin 0 -> 93 bytes objectivec/test/testdata/single_add_gen.py | 19 + 21 files changed, 1261 insertions(+), 1 deletion(-) create mode 100644 objectivec/assert_arc_enabled.mm create mode 100644 objectivec/docs/jazzy_config.yaml create mode 100644 objectivec/docs/main_page.md create mode 100644 objectivec/docs/readme.md create mode 100644 objectivec/error_utils.mm create mode 100644 objectivec/ort_coreml_execution_provider.mm create mode 100644 objectivec/ort_enums.mm create mode 100644 objectivec/ort_env.mm create mode 100644 objectivec/ort_session.mm create mode 100644 objectivec/ort_value.mm create mode 100644 objectivec/ort_xnnpack_execution_provider.mm create mode 100644 objectivec/test/assert_arc_enabled.mm create mode 100644 objectivec/test/assertion_utils.h create mode 100644 objectivec/test/ort_env_test.mm create mode 100644 objectivec/test/ort_session_test.mm create mode 100644 objectivec/test/ort_value_test.mm create mode 100755 objectivec/test/testdata/gen_models.sh create mode 100644 objectivec/test/testdata/single_add.basic.ort create mode 100644 objectivec/test/testdata/single_add.onnx create mode 100644 objectivec/test/testdata/single_add_gen.py diff --git a/Package.swift b/Package.swift index 6d09521..167051f 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - exclude: ["ReadMe.md", "format_objc.sh"], + exclude: ["test", "docs", "ReadMe.md", "format_objc.sh"], cxxSettings: [ .define("SPM_BUILD"), .unsafeFlags(["-std=c++17", diff --git a/objectivec/assert_arc_enabled.mm b/objectivec/assert_arc_enabled.mm new file mode 100644 index 0000000..9aa0bad --- /dev/null +++ b/objectivec/assert_arc_enabled.mm @@ -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."); diff --git a/objectivec/docs/jazzy_config.yaml b/objectivec/docs/jazzy_config.yaml new file mode 100644 index 0000000..676f89d --- /dev/null +++ b/objectivec/docs/jazzy_config.yaml @@ -0,0 +1,13 @@ +module: ONNX Runtime Objective-C API +author: ONNX Runtime Authors +author_url: https://www.onnxruntime.ai +github_url: https://github.com/microsoft/onnxruntime + +objc: true +umbrella_header: ../include/onnxruntime.h +framework_root: .. + +readme: ./main_page.md + +hide_documentation_coverage: true +undocumented_text: "" diff --git a/objectivec/docs/main_page.md b/objectivec/docs/main_page.md new file mode 100644 index 0000000..fdc7c80 --- /dev/null +++ b/objectivec/docs/main_page.md @@ -0,0 +1,5 @@ +# ONNX Runtime Objective-C API + +ONNX Runtime provides an Objective-C API. + +It can be used from Objective-C/C++ or Swift with a bridging header. diff --git a/objectivec/docs/readme.md b/objectivec/docs/readme.md new file mode 100644 index 0000000..5697480 --- /dev/null +++ b/objectivec/docs/readme.md @@ -0,0 +1,17 @@ +# Objective-C API Documentation + +The API should be documented with comments in the [public header files](../include). + +## Documentation Generation + +The [Jazzy](https://github.com/realm/jazzy) tool is used to generate documentation from the code. + +To generate documentation, from the repo root, run: + +```bash +jazzy --config objectivec/docs/jazzy_config.yaml --output +``` + +The generated documentation website files will be in ``. + +[main_page.md](./main_page.md) contains content for the main page of the generated documentation website. diff --git a/objectivec/error_utils.mm b/objectivec/error_utils.mm new file mode 100644 index 0000000..9186326 --- /dev/null +++ b/objectivec/error_utils.mm @@ -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 diff --git a/objectivec/ort_coreml_execution_provider.mm b/objectivec/ort_coreml_execution_provider.mm new file mode 100644 index 0000000..6340fde --- /dev/null +++ b/objectivec/ort_coreml_execution_provider.mm @@ -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(options); + ORTSaveCodeAndDescriptionToError(ORT_FAIL, "CoreML execution provider is not enabled.", error); + return NO; +#endif +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/ort_enums.mm b/objectivec/ort_enums.mm new file mode 100644 index 0000000..0144a33 --- /dev/null +++ b/objectivec/ort_enums.mm @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_enums_internal.h" + +#include + +#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 +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"); +} diff --git a/objectivec/ort_env.mm b/objectivec/ort_env.mm new file mode 100644 index 0000000..cd83ac5 --- /dev/null +++ b/objectivec/ort_env.mm @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_env_internal.h" + +#include + +#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 _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 diff --git a/objectivec/ort_session.mm b/objectivec/ort_session.mm new file mode 100644 index 0000000..c4f57b0 --- /dev/null +++ b/objectivec/ort_session.mm @@ -0,0 +1,361 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_session_internal.h" + +#include +#include + +#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 _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*)inputs + outputs:(NSDictionary*)outputs + runOptions:(nullable ORTRunOptions*)runOptions + error:(NSError**)error { + try { + if (!runOptions) { + runOptions = [[ORTRunOptions alloc] initWithError:error]; + if (!runOptions) { + return NO; + } + } + + std::vector inputNames, outputNames; + std::vector inputValues; + std::vector outputValues; + + for (NSString* inputName in inputs) { + inputNames.push_back(inputName.UTF8String); + inputValues.push_back(static_cast([inputs[inputName] CXXAPIOrtValue])); + } + + for (NSString* outputName in outputs) { + outputNames.push_back(outputName.UTF8String); + outputValues.push_back(static_cast([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*)runWithInputs:(NSDictionary*)inputs + outputNames:(NSSet*)outputNameSet + runOptions:(nullable ORTRunOptions*)runOptions + error:(NSError**)error { + try { + if (!runOptions) { + runOptions = [[ORTRunOptions alloc] initWithError:error]; + if (!runOptions) { + return nil; + } + } + + NSArray* outputNameArray = outputNameSet.allObjects; + + std::vector inputNames, outputNames; + std::vector inputValues; + std::vector outputValues; + + for (NSString* inputName in inputs) { + inputNames.push_back(inputName.UTF8String); + inputValues.push_back(static_cast([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* 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*)inputNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::Input error:error]; +} + +- (nullable NSArray*)overridableInitializerNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::OverridableInitializer error:error]; +} + +- (nullable NSArray*)outputNamesWithError:(NSError**)error { + return [self namesWithType:NamedValueType::Output error:error]; +} + +#pragma mark - Private + +- (nullable NSArray*)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* 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 _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*)providerOptions + error:(NSError**)error { + try { + std::unordered_map 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 _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 diff --git a/objectivec/ort_value.mm b/objectivec/ort_value.mm new file mode 100644 index 0000000..ce77ca7 --- /dev/null +++ b/objectivec/ort_value.mm @@ -0,0 +1,160 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import "ort_value_internal.h" + +#include + +#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 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 _value; + std::optional _typeInfo; +} + +#pragma mark - Public + +- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData + elementType:(ORTTensorElementDataType)elementType + shape:(NSArray*)shape + error:(NSError**)error { + try { + const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + const auto ONNXElementType = PublicToCAPITensorElementType(elementType); + const auto shapeVector = [shape]() { + std::vector 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 diff --git a/objectivec/ort_xnnpack_execution_provider.mm b/objectivec/ort_xnnpack_execution_provider.mm new file mode 100644 index 0000000..324974a --- /dev/null +++ b/objectivec/ort_xnnpack_execution_provider.mm @@ -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 diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm new file mode 100644 index 0000000..9aa0bad --- /dev/null +++ b/objectivec/test/assert_arc_enabled.mm @@ -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."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h new file mode 100644 index 0000000..f2b73e6 --- /dev/null +++ b/objectivec/test/assertion_utils.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#define ORTAssertNullableResultSuccessful(result, error) \ + do { \ + XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertBoolResultSuccessful(result, error) \ + do { \ + XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ + XCTAssertNil(error); \ + } while (0) + +#define ORTAssertNullableResultUnsuccessful(result, error) \ + do { \ + XCTAssertNil(result); \ + XCTAssertNotNil(error); \ + } while (0) + +#define ORTAssertBoolResultUnsuccessful(result, error) \ + do { \ + XCTAssertFalse(result); \ + XCTAssertNotNil(error); \ + } while (0) + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm new file mode 100644 index 0000000..420f55f --- /dev/null +++ b/objectivec/test/ort_env_test.mm @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_env.h" + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTEnvTest : XCTestCase +@end + +@implementation ORTEnvTest +- (void)testGetOrtVersion { + NSString* ver = ORTVersion(); + XCTAssertNotNil(ver); +} + +- (void)testInitOk { + NSError* err = nil; + ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(env, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm new file mode 100644 index 0000000..790ad1c --- /dev/null +++ b/objectivec/test/ort_session_test.mm @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_coreml_execution_provider.h" +#import "ort_xnnpack_execution_provider.h" +#import "ort_env.h" +#import "ort_session.h" +#import "ort_value.h" + +#import "test/assertion_utils.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTSessionTest : XCTestCase + +@property(readonly, nullable) ORTEnv* ortEnv; + +@end + +@implementation ORTSessionTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; + + NSError* err = nil; + _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning + error:&err]; + ORTAssertNullableResultSuccessful(_ortEnv, err); +} + +- (void)tearDown { + _ortEnv = nil; + + [super tearDown]; +} + +// model with an Add op +// inputs: A, B +// output: C = A + B ++ (NSString*)getAddModelPath { + NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; + NSString* path = [bundle pathForResource:@"single_add.basic" + ofType:@"ort"]; + return path; +} + ++ (NSMutableData*)dataWithScalarFloat:(float)value { + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; + return data; +} + ++ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { + NSArray* shape = @[ @1 ]; + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeFloat + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + return ortValue; +} + ++ (ORTSessionOptions*)makeSessionOptions { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(sessionOptions, err); + return sessionOptions; +} + ++ (ORTRunOptions*)makeRunOptions { + NSError* err = nil; + ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; + ORTAssertNullableResultSuccessful(runOptions, err); + return runOptions; +} + +- (void)testInitAndRunWithPreallocatedOutputOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultSuccessful(runResult, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testInitAndRunOk { + NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; + + ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; + ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSDictionary* outputs = + [session runWithInputs:@{@"A" : a, @"B" : b} + outputNames:[NSSet setWithArray:@[ @"C" ]] + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertNullableResultSuccessful(outputs, err); + + ORTValue* cOutput = outputs[@"C"]; + XCTAssertNotNil(cOutput); + + NSData* cData = [cOutput tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(cData, err); + + const float cExpected = 3.0f; + float cActual; + memcpy(&cActual, cData.bytes, sizeof(float)); + XCTAssertEqual(cActual, cExpected); +} + +- (void)testGetNamesOk { + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + NSArray* inputNames = [session inputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(inputNames, err); + XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); + + NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; + ORTAssertNullableResultSuccessful(overridableInitializerNames, err); + XCTAssertEqualObjects(overridableInitializerNames, (@[])); + + NSArray* outputNames = [session outputNamesWithError:&err]; + ORTAssertNullableResultSuccessful(outputNames, err); + XCTAssertEqualObjects(outputNames, (@[ @"C" ])); +} + +- (void)testInitFailsWithInvalidPath { + NSString* invalidModelPath = @"invalid/path/to/model.ort"; + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:invalidModelPath + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultUnsuccessful(session, err); +} + +- (void)testRunFailsWithInvalidInput { + NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; + NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; + + ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; + ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; + + NSError* err = nil; + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:[ORTSessionTest makeSessionOptions] + error:&err]; + ORTAssertNullableResultSuccessful(session, err); + + BOOL runResult = [session runWithInputs:@{@"D" : d} + outputs:@{@"C" : c} + runOptions:[ORTSessionTest makeRunOptions] + error:&err]; + ORTAssertBoolResultUnsuccessful(runResult, err); +} + +- (void)testAppendCoreMLEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; + coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option + + BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions + error:&err]; + + if (!ORTIsCoreMLExecutionProviderAvailable()) { + ORTAssertBoolResultUnsuccessful(appendResult, err); + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} + +- (void)testAppendXnnpackEP { + NSError* err = nil; + ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; + ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; + XnnpackOptions.intra_op_num_threads = 2; + + BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions + error:&err]; + // Without xnnpack EP in building also can pass the test + NSString* err_msg = [err localizedDescription]; + if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { + return; + } + + ORTAssertBoolResultSuccessful(appendResult, err); + + ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv + modelPath:[ORTSessionTest getAddModelPath] + sessionOptions:sessionOptions + error:&err]; + ORTAssertNullableResultSuccessful(session, err); +} +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm new file mode 100644 index 0000000..734ad39 --- /dev/null +++ b/objectivec/test/ort_value_test.mm @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#import + +#import "ort_value.h" + +#include + +#import "test/assertion_utils.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface ORTValueTest : XCTestCase +@end + +@implementation ORTValueTest + +- (void)setUp { + [super setUp]; + + self.continueAfterFailure = NO; +} + +- (void)testInitTensorOk { + int32_t value = 42; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value + length:sizeof(int32_t)]; + NSArray* shape = @[ @1 ]; + + const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:elementType + shape:shape + error:&err]; + ORTAssertNullableResultSuccessful(ortValue, err); + + auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { + XCTAssertEqual(tensorInfo.elementType, elementType); + XCTAssertEqualObjects(tensorInfo.shape, shape); + }; + + ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(typeInfo, err); + XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); + XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); + checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); + + ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; + ORTAssertNullableResultSuccessful(tensorInfo, err); + checkTensorInfo(tensorInfo); + + NSData* actualData = [ortValue tensorDataWithError:&err]; + ORTAssertNullableResultSuccessful(actualData, err); + XCTAssertEqual(actualData.length, sizeof(int32_t)); + int32_t actualValue; + memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); + XCTAssertEqual(actualValue, value); +} + +- (void)testInitTensorFailsWithDataSmallerThanShape { + std::vector values{1, 2, 3, 4}; + NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() + length:values.size() * sizeof(int32_t)]; + NSArray* shape = @[ @2, @3 ]; // too large + + NSError* err = nil; + ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data + elementType:ORTTensorElementDataTypeInt32 + shape:shape + error:&err]; + ORTAssertNullableResultUnsuccessful(ortValue, err); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh new file mode 100755 index 0000000..0a58ca8 --- /dev/null +++ b/objectivec/test/testdata/gen_models.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -e + +# Get directory this script is in +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd ${DIR} + +python3 ./single_add_gen.py + +ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort new file mode 100644 index 0000000000000000000000000000000000000000..f622784b35366ea8f0c33ccbdb513b5d6f7df7c1 GIT binary patch literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx new file mode 100644 index 0000000000000000000000000000000000000000..82e8fe669e0d84b6111f678b0742a552d820269b GIT binary patch literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# literal 0 HcmV?d00001 diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py new file mode 100644 index 0000000..15b4372 --- /dev/null +++ b/objectivec/test/testdata/single_add_gen.py @@ -0,0 +1,19 @@ +import onnx +from onnx import TensorProto, helper + +graph = helper.make_graph( + [ # nodes + helper.make_node("Add", ["A", "B"], ["C"], "Add"), + ], + "SingleAdd", # name + [ # inputs + helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), + helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), + ], + [ # outputs + helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), + ], +) + +model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) +onnx.save(model, r"single_add.onnx") From 2d19b7546348e3155616624542acd610f0776fbc Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 11:30:22 -0700 Subject: [PATCH 63/70] remove test/ docs/ etc. --- Package.swift | 2 +- objectivec/docs/jazzy_config.yaml | 13 - objectivec/docs/main_page.md | 5 - objectivec/docs/readme.md | 17 -- objectivec/test/assert_arc_enabled.mm | 4 - objectivec/test/assertion_utils.h | 32 --- objectivec/test/ort_env_test.mm | 30 --- objectivec/test/ort_session_test.mm | 243 ------------------ objectivec/test/ort_value_test.mm | 79 ------ objectivec/test/testdata/gen_models.sh | 12 - objectivec/test/testdata/single_add.basic.ort | Bin 1296 -> 0 bytes objectivec/test/testdata/single_add.onnx | Bin 93 -> 0 bytes objectivec/test/testdata/single_add_gen.py | 19 -- 13 files changed, 1 insertion(+), 455 deletions(-) delete mode 100644 objectivec/docs/jazzy_config.yaml delete mode 100644 objectivec/docs/main_page.md delete mode 100644 objectivec/docs/readme.md delete mode 100644 objectivec/test/assert_arc_enabled.mm delete mode 100644 objectivec/test/assertion_utils.h delete mode 100644 objectivec/test/ort_env_test.mm delete mode 100644 objectivec/test/ort_session_test.mm delete mode 100644 objectivec/test/ort_value_test.mm delete mode 100755 objectivec/test/testdata/gen_models.sh delete mode 100644 objectivec/test/testdata/single_add.basic.ort delete mode 100644 objectivec/test/testdata/single_add.onnx delete mode 100644 objectivec/test/testdata/single_add_gen.py diff --git a/Package.swift b/Package.swift index 167051f..6d09521 100644 --- a/Package.swift +++ b/Package.swift @@ -31,7 +31,7 @@ let package = Package( .target(name: "OnnxRuntimeBindings", dependencies: ["onnxruntime"], path: "objectivec", - exclude: ["test", "docs", "ReadMe.md", "format_objc.sh"], + exclude: ["ReadMe.md", "format_objc.sh"], cxxSettings: [ .define("SPM_BUILD"), .unsafeFlags(["-std=c++17", diff --git a/objectivec/docs/jazzy_config.yaml b/objectivec/docs/jazzy_config.yaml deleted file mode 100644 index 676f89d..0000000 --- a/objectivec/docs/jazzy_config.yaml +++ /dev/null @@ -1,13 +0,0 @@ -module: ONNX Runtime Objective-C API -author: ONNX Runtime Authors -author_url: https://www.onnxruntime.ai -github_url: https://github.com/microsoft/onnxruntime - -objc: true -umbrella_header: ../include/onnxruntime.h -framework_root: .. - -readme: ./main_page.md - -hide_documentation_coverage: true -undocumented_text: "" diff --git a/objectivec/docs/main_page.md b/objectivec/docs/main_page.md deleted file mode 100644 index fdc7c80..0000000 --- a/objectivec/docs/main_page.md +++ /dev/null @@ -1,5 +0,0 @@ -# ONNX Runtime Objective-C API - -ONNX Runtime provides an Objective-C API. - -It can be used from Objective-C/C++ or Swift with a bridging header. diff --git a/objectivec/docs/readme.md b/objectivec/docs/readme.md deleted file mode 100644 index 5697480..0000000 --- a/objectivec/docs/readme.md +++ /dev/null @@ -1,17 +0,0 @@ -# Objective-C API Documentation - -The API should be documented with comments in the [public header files](../include). - -## Documentation Generation - -The [Jazzy](https://github.com/realm/jazzy) tool is used to generate documentation from the code. - -To generate documentation, from the repo root, run: - -```bash -jazzy --config objectivec/docs/jazzy_config.yaml --output -``` - -The generated documentation website files will be in ``. - -[main_page.md](./main_page.md) contains content for the main page of the generated documentation website. diff --git a/objectivec/test/assert_arc_enabled.mm b/objectivec/test/assert_arc_enabled.mm deleted file mode 100644 index 9aa0bad..0000000 --- a/objectivec/test/assert_arc_enabled.mm +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled."); diff --git a/objectivec/test/assertion_utils.h b/objectivec/test/assertion_utils.h deleted file mode 100644 index f2b73e6..0000000 --- a/objectivec/test/assertion_utils.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -NS_ASSUME_NONNULL_BEGIN - -#define ORTAssertNullableResultSuccessful(result, error) \ - do { \ - XCTAssertNotNil(result, @"Expected non-nil result but got nil. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertBoolResultSuccessful(result, error) \ - do { \ - XCTAssertTrue(result, @"Expected true result but got false. Error: %@", error); \ - XCTAssertNil(error); \ - } while (0) - -#define ORTAssertNullableResultUnsuccessful(result, error) \ - do { \ - XCTAssertNil(result); \ - XCTAssertNotNil(error); \ - } while (0) - -#define ORTAssertBoolResultUnsuccessful(result, error) \ - do { \ - XCTAssertFalse(result); \ - XCTAssertNotNil(error); \ - } while (0) - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_env_test.mm b/objectivec/test/ort_env_test.mm deleted file mode 100644 index 420f55f..0000000 --- a/objectivec/test/ort_env_test.mm +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_env.h" - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTEnvTest : XCTestCase -@end - -@implementation ORTEnvTest -- (void)testGetOrtVersion { - NSString* ver = ORTVersion(); - XCTAssertNotNil(ver); -} - -- (void)testInitOk { - NSError* err = nil; - ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(env, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_session_test.mm b/objectivec/test/ort_session_test.mm deleted file mode 100644 index 790ad1c..0000000 --- a/objectivec/test/ort_session_test.mm +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_coreml_execution_provider.h" -#import "ort_xnnpack_execution_provider.h" -#import "ort_env.h" -#import "ort_session.h" -#import "ort_value.h" - -#import "test/assertion_utils.h" - -#include - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTSessionTest : XCTestCase - -@property(readonly, nullable) ORTEnv* ortEnv; - -@end - -@implementation ORTSessionTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; - - NSError* err = nil; - _ortEnv = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning - error:&err]; - ORTAssertNullableResultSuccessful(_ortEnv, err); -} - -- (void)tearDown { - _ortEnv = nil; - - [super tearDown]; -} - -// model with an Add op -// inputs: A, B -// output: C = A + B -+ (NSString*)getAddModelPath { - NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]]; - NSString* path = [bundle pathForResource:@"single_add.basic" - ofType:@"ort"]; - return path; -} - -+ (NSMutableData*)dataWithScalarFloat:(float)value { - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value length:sizeof(value)]; - return data; -} - -+ (ORTValue*)ortValueWithScalarFloatData:(NSMutableData*)data { - NSArray* shape = @[ @1 ]; - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeFloat - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - return ortValue; -} - -+ (ORTSessionOptions*)makeSessionOptions { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [[ORTSessionOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(sessionOptions, err); - return sessionOptions; -} - -+ (ORTRunOptions*)makeRunOptions { - NSError* err = nil; - ORTRunOptions* runOptions = [[ORTRunOptions alloc] initWithError:&err]; - ORTAssertNullableResultSuccessful(runOptions, err); - return runOptions; -} - -- (void)testInitAndRunWithPreallocatedOutputOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"A" : a, @"B" : b} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultSuccessful(runResult, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testInitAndRunOk { - NSMutableData* aData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* bData = [ORTSessionTest dataWithScalarFloat:2.0f]; - - ORTValue* a = [ORTSessionTest ortValueWithScalarFloatData:aData]; - ORTValue* b = [ORTSessionTest ortValueWithScalarFloatData:bData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSDictionary* outputs = - [session runWithInputs:@{@"A" : a, @"B" : b} - outputNames:[NSSet setWithArray:@[ @"C" ]] - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertNullableResultSuccessful(outputs, err); - - ORTValue* cOutput = outputs[@"C"]; - XCTAssertNotNil(cOutput); - - NSData* cData = [cOutput tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(cData, err); - - const float cExpected = 3.0f; - float cActual; - memcpy(&cActual, cData.bytes, sizeof(float)); - XCTAssertEqual(cActual, cExpected); -} - -- (void)testGetNamesOk { - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - NSArray* inputNames = [session inputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(inputNames, err); - XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ])); - - NSArray* overridableInitializerNames = [session overridableInitializerNamesWithError:&err]; - ORTAssertNullableResultSuccessful(overridableInitializerNames, err); - XCTAssertEqualObjects(overridableInitializerNames, (@[])); - - NSArray* outputNames = [session outputNamesWithError:&err]; - ORTAssertNullableResultSuccessful(outputNames, err); - XCTAssertEqualObjects(outputNames, (@[ @"C" ])); -} - -- (void)testInitFailsWithInvalidPath { - NSString* invalidModelPath = @"invalid/path/to/model.ort"; - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:invalidModelPath - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultUnsuccessful(session, err); -} - -- (void)testRunFailsWithInvalidInput { - NSMutableData* dData = [ORTSessionTest dataWithScalarFloat:1.0f]; - NSMutableData* cData = [ORTSessionTest dataWithScalarFloat:0.0f]; - - ORTValue* d = [ORTSessionTest ortValueWithScalarFloatData:dData]; - ORTValue* c = [ORTSessionTest ortValueWithScalarFloatData:cData]; - - NSError* err = nil; - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:[ORTSessionTest makeSessionOptions] - error:&err]; - ORTAssertNullableResultSuccessful(session, err); - - BOOL runResult = [session runWithInputs:@{@"D" : d} - outputs:@{@"C" : c} - runOptions:[ORTSessionTest makeRunOptions] - error:&err]; - ORTAssertBoolResultUnsuccessful(runResult, err); -} - -- (void)testAppendCoreMLEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTCoreMLExecutionProviderOptions* coreMLOptions = [[ORTCoreMLExecutionProviderOptions alloc] init]; - coreMLOptions.enableOnSubgraphs = YES; // set an arbitrary option - - BOOL appendResult = [sessionOptions appendCoreMLExecutionProviderWithOptions:coreMLOptions - error:&err]; - - if (!ORTIsCoreMLExecutionProviderAvailable()) { - ORTAssertBoolResultUnsuccessful(appendResult, err); - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} - -- (void)testAppendXnnpackEP { - NSError* err = nil; - ORTSessionOptions* sessionOptions = [ORTSessionTest makeSessionOptions]; - ORTXnnpackExecutionProviderOptions* XnnpackOptions = [[ORTXnnpackExecutionProviderOptions alloc] init]; - XnnpackOptions.intra_op_num_threads = 2; - - BOOL appendResult = [sessionOptions appendXnnpackExecutionProviderWithOptions:XnnpackOptions - error:&err]; - // Without xnnpack EP in building also can pass the test - NSString* err_msg = [err localizedDescription]; - if (!appendResult && [err_msg containsString:@"XNNPACK execution provider is not supported in this build. "]) { - return; - } - - ORTAssertBoolResultSuccessful(appendResult, err); - - ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv - modelPath:[ORTSessionTest getAddModelPath] - sessionOptions:sessionOptions - error:&err]; - ORTAssertNullableResultSuccessful(session, err); -} -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/ort_value_test.mm b/objectivec/test/ort_value_test.mm deleted file mode 100644 index 734ad39..0000000 --- a/objectivec/test/ort_value_test.mm +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#import - -#import "ort_value.h" - -#include - -#import "test/assertion_utils.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface ORTValueTest : XCTestCase -@end - -@implementation ORTValueTest - -- (void)setUp { - [super setUp]; - - self.continueAfterFailure = NO; -} - -- (void)testInitTensorOk { - int32_t value = 42; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:&value - length:sizeof(int32_t)]; - NSArray* shape = @[ @1 ]; - - const ORTTensorElementDataType elementType = ORTTensorElementDataTypeInt32; - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:elementType - shape:shape - error:&err]; - ORTAssertNullableResultSuccessful(ortValue, err); - - auto checkTensorInfo = [&](ORTTensorTypeAndShapeInfo* tensorInfo) { - XCTAssertEqual(tensorInfo.elementType, elementType); - XCTAssertEqualObjects(tensorInfo.shape, shape); - }; - - ORTValueTypeInfo* typeInfo = [ortValue typeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(typeInfo, err); - XCTAssertEqual(typeInfo.type, ORTValueTypeTensor); - XCTAssertNotNil(typeInfo.tensorTypeAndShapeInfo); - checkTensorInfo(typeInfo.tensorTypeAndShapeInfo); - - ORTTensorTypeAndShapeInfo* tensorInfo = [ortValue tensorTypeAndShapeInfoWithError:&err]; - ORTAssertNullableResultSuccessful(tensorInfo, err); - checkTensorInfo(tensorInfo); - - NSData* actualData = [ortValue tensorDataWithError:&err]; - ORTAssertNullableResultSuccessful(actualData, err); - XCTAssertEqual(actualData.length, sizeof(int32_t)); - int32_t actualValue; - memcpy(&actualValue, actualData.bytes, sizeof(int32_t)); - XCTAssertEqual(actualValue, value); -} - -- (void)testInitTensorFailsWithDataSmallerThanShape { - std::vector values{1, 2, 3, 4}; - NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data() - length:values.size() * sizeof(int32_t)]; - NSArray* shape = @[ @2, @3 ]; // too large - - NSError* err = nil; - ORTValue* ortValue = [[ORTValue alloc] initWithTensorData:data - elementType:ORTTensorElementDataTypeInt32 - shape:shape - error:&err]; - ORTAssertNullableResultUnsuccessful(ortValue, err); -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/objectivec/test/testdata/gen_models.sh b/objectivec/test/testdata/gen_models.sh deleted file mode 100755 index 0a58ca8..0000000 --- a/objectivec/test/testdata/gen_models.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash - -set -e - -# Get directory this script is in -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -cd ${DIR} - -python3 ./single_add_gen.py - -ORT_CONVERT_ONNX_MODELS_TO_ORT_OPTIMIZATION_LEVEL=basic python3 -m onnxruntime.tools.convert_onnx_models_to_ort --optimization_style=Fixed . diff --git a/objectivec/test/testdata/single_add.basic.ort b/objectivec/test/testdata/single_add.basic.ort deleted file mode 100644 index f622784b35366ea8f0c33ccbdb513b5d6f7df7c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1296 zcmaJ=L2DCH5T59w+gK&qP=ZMC5X6H#a!@S6gSGW228qz?vUxTO&D*eD(+Gkdq9fHT2w9Z|5JC$eX^YH( zlR%{XYq5Zk8bCRK-6(YKQNIB6HiyIBeUTjJWFiO82f%rt3)}>_&xlYiY8;GOSmb7$ z&l6~_CL&tWWB~H``e>1B;n$lD6g595VDqaf9Yo#GIDe}^8Mfg=^Z{}(59JBa!5-}v zK)DTw)V0wS&J3ry_RPrw0VxVu)->>nX{L6ljZwugT zn6K>BBj`Na1Xh4|F#13TU_ZV9N5By10*w3i+xH!++T=^KT{C%=r&&BQQEna2_~=2S zi*eV1I31gD5@+dt`XV=WHnCYUwl0tMa9HtY5MwR_r($65RQ%|}{~$_C>fFpsGCNJ| zfyuKdaf#c-k-R_S&w5M$s^44qU1dPA$jzB){(Y0U+-5G?Gj4Pc)8#w-`Bu5;%UPDZ nW85dyzl#&~J%&)fHONzUGA<@%sQ;t)_p@e%kMWx4xd-D9DJ`oI diff --git a/objectivec/test/testdata/single_add.onnx b/objectivec/test/testdata/single_add.onnx deleted file mode 100644 index 82e8fe669e0d84b6111f678b0742a552d820269b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93 zcmd;Jw+iMG=3;c@VssK>be3XvOi57!5kj27nR)3ssX%5FKTuwXi;IJUQHX_$iGvX& U;DjuY1Qc*a7I0$WVi4c~0E&7GKL7v# diff --git a/objectivec/test/testdata/single_add_gen.py b/objectivec/test/testdata/single_add_gen.py deleted file mode 100644 index 15b4372..0000000 --- a/objectivec/test/testdata/single_add_gen.py +++ /dev/null @@ -1,19 +0,0 @@ -import onnx -from onnx import TensorProto, helper - -graph = helper.make_graph( - [ # nodes - helper.make_node("Add", ["A", "B"], ["C"], "Add"), - ], - "SingleAdd", # name - [ # inputs - helper.make_tensor_value_info("A", TensorProto.FLOAT, [1]), - helper.make_tensor_value_info("B", TensorProto.FLOAT, [1]), - ], - [ # outputs - helper.make_tensor_value_info("C", TensorProto.FLOAT, [1]), - ], -) - -model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 12)]) -onnx.save(model, r"single_add.onnx") From cb9b5836b1bca38b5a41ad21e8034583f55b9a40 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 12:24:25 -0700 Subject: [PATCH 64/70] rm version.txt --- version.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 version.txt diff --git a/version.txt b/version.txt deleted file mode 100644 index d19d089..0000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.15.0 \ No newline at end of file From 7007553ecdbca0acf0d06d28edafa4009ab41f53 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 12:52:36 -0700 Subject: [PATCH 65/70] use and add readme --- .pipelines/mac-ios-swift-ci-pipeline.yml | 3 +-- README.md | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.pipelines/mac-ios-swift-ci-pipeline.yml b/.pipelines/mac-ios-swift-ci-pipeline.yml index 516623f..44c3be6 100644 --- a/.pipelines/mac-ios-swift-ci-pipeline.yml +++ b/.pipelines/mac-ios-swift-ci-pipeline.yml @@ -43,8 +43,7 @@ stages: - script: | set -e -x cd "$(Build.ArtifactStagingDirectory)/$(artifactsName)" - ARTIFACTS_LIST=$(ls) - POD_ARCHIVE=$(echo "${ARTIFACTS_LIST}" | sed -n '5p') + POD_ARCHIVE=$(find . -name "pod-archive-onnxruntime-c*.zip") shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" diff --git a/README.md b/README.md index 85af6ad..57c6dc4 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ A light-weight repository for providing [Swift Package Manager (SPM)](https://ww 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 This project welcomes contributions and suggestions. Most contributions require you to agree to a From df05c923eecf72a32ff1f02da0c932099564abc9 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 14:20:58 -0700 Subject: [PATCH 66/70] add separate ci for latest main local testing --- ...> mac-ios-spm-dev-validation-pipeline.yml} | 49 ++++++------------- ...ac-ios-spm-release-validation-pipeline.yml | 26 ++++++++++ 2 files changed, 42 insertions(+), 33 deletions(-) rename .pipelines/{mac-ios-swift-ci-pipeline.yml => mac-ios-spm-dev-validation-pipeline.yml} (71%) create mode 100644 .pipelines/mac-ios-spm-release-validation-pipeline.yml diff --git a/.pipelines/mac-ios-swift-ci-pipeline.yml b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml similarity index 71% rename from .pipelines/mac-ios-swift-ci-pipeline.yml rename to .pipelines/mac-ios-spm-dev-validation-pipeline.yml index 44c3be6..0d44a32 100644 --- a/.pipelines/mac-ios-swift-ci-pipeline.yml +++ b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml @@ -1,6 +1,3 @@ -stages: -- stage: SPM_IOS_Local_Pod_Testing - dependsOn: [] jobs: - job: j displayName: "Test with latest local ORT native pod" @@ -10,7 +7,7 @@ stages: variables: xcodeVersion: "14.3" - artifactsName: "ios_packaging_artifacts" #TODO: Add `_full` suffix when syncing to latest main + artifactsName: "ios_packaging_artifacts_full" timeoutInMinutes: 60 @@ -19,6 +16,16 @@ stages: 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" + # 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. @@ -28,7 +35,7 @@ stages: project: 'Lotus' definition: 995 #'definitionid' is obtained from `System.DefinitionId` of ORT CI: onnxruntime-ios-packaging-pipeline buildVersionToDownload: 'latest' - branchName: 'rel-1.15.0' + branchName: 'main' targetPath: '$(Build.ArtifactStagingDirectory)' - script: | @@ -47,42 +54,18 @@ stages: shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" - cd "$(Build.SourcesDirectory)" + cd "$(Build.SourcesDirectory)"/tmp 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)" + 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' - -- stage: SPM_IOS_Release_Pod_Testing - dependsOn: [] - 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' + rm -rf tmp/. workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Test Package.swift usage" + displayName: "Sparse checkout objectivec/ swift/ folders from latest ORT main repository" - template: templates/component-governance-component-detection-steps.yml parameters : diff --git a/.pipelines/mac-ios-spm-release-validation-pipeline.yml b/.pipelines/mac-ios-spm-release-validation-pipeline.yml new file mode 100644 index 0000000..f62f79c --- /dev/null +++ b/.pipelines/mac-ios-spm-release-validation-pipeline.yml @@ -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' \ No newline at end of file From 2f2ac39c10f71a378a3018abc2dc61f04c8e1795 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 14:27:40 -0700 Subject: [PATCH 67/70] fix quotes --- .pipelines/mac-ios-spm-dev-validation-pipeline.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml index 0d44a32..0fcb828 100644 --- a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml +++ b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml @@ -54,12 +54,12 @@ shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" - cd "$(Build.SourcesDirectory)"/tmp + cd "$(Build.SourcesDirectory)/tmp" 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 + workingDirectory: "$(Build.SourcesDirectory)/tmp" displayName: "Print ORT iOS Pod checksum and Test Package.swift usage" - script: | From 9150411089b6707d7b2d6b9a4565e0eeb64f1e84 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 14:42:36 -0700 Subject: [PATCH 68/70] fix --- .pipelines/mac-ios-spm-dev-validation-pipeline.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml index 0fcb828..2a140e2 100644 --- a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml +++ b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml @@ -25,7 +25,12 @@ 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. @@ -54,7 +59,7 @@ shasum -a 256 "$(Build.ArtifactStagingDirectory)/$(artifactsName)/${POD_ARCHIVE}" - cd "$(Build.SourcesDirectory)/tmp" + 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' From 9346c78a2d82d4bff2b72ec5f6ede432bb7d0c01 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 14:46:40 -0700 Subject: [PATCH 69/70] fix --- .pipelines/mac-ios-spm-dev-validation-pipeline.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml index 2a140e2..09d1d7f 100644 --- a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml +++ b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml @@ -26,7 +26,7 @@ workingDirectory: "$(Build.SourcesDirectory)" displayName: "Sparse checkout objectivec/ swift/ folders from latest ORT main repository" - - script: | + - script: | ls -R "$(Build.SourcesDirectory)/tmp/onnxruntime" workingDirectory: "$(Build.SourcesDirectory)/tmp" displayName: "List sparse checkout repo contents" From 19f678db0d3742f3262839d4d274df7d88c04ae8 Mon Sep 17 00:00:00 2001 From: rachguo Date: Thu, 20 Jul 2023 14:54:22 -0700 Subject: [PATCH 70/70] fix --- .pipelines/mac-ios-spm-dev-validation-pipeline.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml index 09d1d7f..8a801cd 100644 --- a/.pipelines/mac-ios-spm-dev-validation-pipeline.yml +++ b/.pipelines/mac-ios-spm-dev-validation-pipeline.yml @@ -67,11 +67,6 @@ workingDirectory: "$(Build.SourcesDirectory)/tmp" displayName: "Print ORT iOS Pod checksum and Test Package.swift usage" - - script: | - rm -rf tmp/. - workingDirectory: "$(Build.SourcesDirectory)" - displayName: "Sparse checkout objectivec/ swift/ folders from latest ORT main repository" - - template: templates/component-governance-component-detection-steps.yml parameters : condition : 'succeeded' \ No newline at end of file