Revert "remove not required files"

This reverts commit 071c82ffd7.
This commit is contained in:
rachguo
2023-07-19 15:12:23 -07:00
parent 071c82ffd7
commit f3396b6ce4
21 changed files with 1261 additions and 1 deletions
+1 -1
View File
@@ -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",
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled.");
+13
View File
@@ -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: ""
+5
View File
@@ -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.
+17
View File
@@ -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 <output directory>
```
The generated documentation website files will be in `<output directory>`.
[main_page.md](./main_page.md) contains content for the main page of the generated documentation website.
+29
View File
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "error_utils.h"
NS_ASSUME_NONNULL_BEGIN
static NSString* const kOrtErrorDomain = @"onnxruntime";
void ORTSaveCodeAndDescriptionToError(int code, const char* descriptionCstr, NSError** error) {
if (!error) return;
NSString* description = [NSString stringWithCString:descriptionCstr
encoding:NSASCIIStringEncoding];
*error = [NSError errorWithDomain:kOrtErrorDomain
code:code
userInfo:@{NSLocalizedDescriptionKey : description}];
}
void ORTSaveOrtExceptionToError(const Ort::Exception& e, NSError** error) {
ORTSaveCodeAndDescriptionToError(e.GetOrtErrorCode(), e.what(), error);
}
void ORTSaveExceptionToError(const std::exception& e, NSError** error) {
ORTSaveCodeAndDescriptionToError(ORT_RUNTIME_EXCEPTION, e.what(), error);
}
NS_ASSUME_NONNULL_END
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_coreml_execution_provider.h"
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_session_internal.h"
NS_ASSUME_NONNULL_BEGIN
BOOL ORTIsCoreMLExecutionProviderAvailable() {
return ORT_OBJC_API_COREML_EP_AVAILABLE ? YES : NO;
}
@implementation ORTCoreMLExecutionProviderOptions
@end
@implementation ORTSessionOptions (ORTSessionOptionsCoreMLEP)
- (BOOL)appendCoreMLExecutionProviderWithOptions:(ORTCoreMLExecutionProviderOptions*)options
error:(NSError**)error {
#if ORT_OBJC_API_COREML_EP_AVAILABLE
try {
const uint32_t flags =
(options.useCPUOnly ? COREML_FLAG_USE_CPU_ONLY : 0) |
(options.enableOnSubgraphs ? COREML_FLAG_ENABLE_ON_SUBGRAPH : 0) |
(options.onlyEnableForDevicesWithANE ? COREML_FLAG_ONLY_ENABLE_DEVICE_WITH_ANE : 0);
Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CoreML(
[self CXXAPIOrtSessionOptions], flags));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error);
#else // !ORT_OBJC_API_COREML_EP_AVAILABLE
static_cast<void>(options);
ORTSaveCodeAndDescriptionToError(ORT_FAIL, "CoreML execution provider is not enabled.", error);
return NO;
#endif
}
@end
NS_ASSUME_NONNULL_END
+133
View File
@@ -0,0 +1,133 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_enums_internal.h"
#include <algorithm>
#import "cxx_api.h"
namespace {
struct LoggingLevelInfo {
ORTLoggingLevel logging_level;
OrtLoggingLevel capi_logging_level;
};
// supported ORT logging levels
// define the mapping from ORTLoggingLevel to C API OrtLoggingLevel here
constexpr LoggingLevelInfo kLoggingLevelInfos[]{
{ORTLoggingLevelVerbose, ORT_LOGGING_LEVEL_VERBOSE},
{ORTLoggingLevelInfo, ORT_LOGGING_LEVEL_INFO},
{ORTLoggingLevelWarning, ORT_LOGGING_LEVEL_WARNING},
{ORTLoggingLevelError, ORT_LOGGING_LEVEL_ERROR},
{ORTLoggingLevelFatal, ORT_LOGGING_LEVEL_FATAL},
};
struct ValueTypeInfo {
ORTValueType type;
ONNXType capi_type;
};
// supported ORT value types
// define the mapping from ORTValueType to C API ONNXType here
constexpr ValueTypeInfo kValueTypeInfos[]{
{ORTValueTypeUnknown, ONNX_TYPE_UNKNOWN},
{ORTValueTypeTensor, ONNX_TYPE_TENSOR},
};
struct TensorElementTypeInfo {
ORTTensorElementDataType type;
ONNXTensorElementDataType capi_type;
size_t element_size;
};
// supported ORT tensor element data types
// define the mapping from ORTTensorElementDataType to C API ONNXTensorElementDataType here
constexpr TensorElementTypeInfo kElementTypeInfos[]{
{ORTTensorElementDataTypeUndefined, ONNX_TENSOR_ELEMENT_DATA_TYPE_UNDEFINED, 0},
{ORTTensorElementDataTypeFloat, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, sizeof(float)},
{ORTTensorElementDataTypeInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, sizeof(int8_t)},
{ORTTensorElementDataTypeUInt8, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT8, sizeof(uint8_t)},
{ORTTensorElementDataTypeInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, sizeof(int32_t)},
{ORTTensorElementDataTypeUInt32, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT32, sizeof(uint32_t)},
{ORTTensorElementDataTypeInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, sizeof(int64_t)},
{ORTTensorElementDataTypeUInt64, ONNX_TENSOR_ELEMENT_DATA_TYPE_UINT64, sizeof(uint64_t)},
};
struct GraphOptimizationLevelInfo {
ORTGraphOptimizationLevel opt_level;
GraphOptimizationLevel capi_opt_level;
};
// ORT graph optimization levels
// define the mapping from ORTGraphOptimizationLevel to C API GraphOptimizationLevel here
constexpr GraphOptimizationLevelInfo kGraphOptimizationLevelInfos[]{
{ORTGraphOptimizationLevelNone, ORT_DISABLE_ALL},
{ORTGraphOptimizationLevelBasic, ORT_ENABLE_BASIC},
{ORTGraphOptimizationLevelExtended, ORT_ENABLE_EXTENDED},
{ORTGraphOptimizationLevelAll, ORT_ENABLE_ALL},
};
template <typename Container, typename SelectFn, typename TransformFn>
auto SelectAndTransform(
const Container& container, SelectFn select_fn, TransformFn transform_fn,
const char* not_found_msg)
-> decltype(transform_fn(*std::begin(container))) {
const auto it = std::find_if(
std::begin(container), std::end(container), select_fn);
if (it == std::end(container)) {
ORT_CXX_API_THROW(not_found_msg, ORT_NOT_IMPLEMENTED);
}
return transform_fn(*it);
}
} // namespace
OrtLoggingLevel PublicToCAPILoggingLevel(ORTLoggingLevel logging_level) {
return SelectAndTransform(
kLoggingLevelInfos,
[logging_level](const auto& logging_level_info) { return logging_level_info.logging_level == logging_level; },
[](const auto& logging_level_info) { return logging_level_info.capi_logging_level; },
"unsupported logging level");
}
ORTValueType CAPIToPublicValueType(ONNXType capi_type) {
return SelectAndTransform(
kValueTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.type; },
"unsupported value type");
}
ONNXTensorElementDataType PublicToCAPITensorElementType(ORTTensorElementDataType type) {
return SelectAndTransform(
kElementTypeInfos,
[type](const auto& type_info) { return type_info.type == type; },
[](const auto& type_info) { return type_info.capi_type; },
"unsupported tensor element type");
}
ORTTensorElementDataType CAPIToPublicTensorElementType(ONNXTensorElementDataType capi_type) {
return SelectAndTransform(
kElementTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.type; },
"unsupported tensor element type");
}
size_t SizeOfCAPITensorElementType(ONNXTensorElementDataType capi_type) {
return SelectAndTransform(
kElementTypeInfos,
[capi_type](const auto& type_info) { return type_info.capi_type == capi_type; },
[](const auto& type_info) { return type_info.element_size; },
"unsupported tensor element type");
}
GraphOptimizationLevel PublicToCAPIGraphOptimizationLevel(ORTGraphOptimizationLevel opt_level) {
return SelectAndTransform(
kGraphOptimizationLevelInfos,
[opt_level](const auto& opt_level_info) { return opt_level_info.opt_level == opt_level; },
[](const auto& opt_level_info) { return opt_level_info.capi_opt_level; },
"unsupported graph optimization level");
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_env_internal.h"
#include <optional>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
NS_ASSUME_NONNULL_BEGIN
NSString* ORTVersion(void) {
std::string result = OrtGetApiBase()->GetVersionString();
return [NSString stringWithUTF8String:result.c_str()];
}
@implementation ORTEnv {
std::optional<Ort::Env> _env;
}
- (nullable instancetype)initWithLoggingLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
const auto CAPILoggingLevel = PublicToCAPILoggingLevel(loggingLevel);
_env = Ort::Env{CAPILoggingLevel};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (Ort::Env&)CXXAPIOrtEnv {
return *_env;
}
@end
NS_ASSUME_NONNULL_END
+361
View File
@@ -0,0 +1,361 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_session_internal.h"
#include <optional>
#include <vector>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
#import "ort_env_internal.h"
#import "ort_value_internal.h"
namespace {
enum class NamedValueType {
Input,
OverridableInitializer,
Output,
};
} // namespace
NS_ASSUME_NONNULL_BEGIN
@implementation ORTSession {
std::optional<Ort::Session> _session;
}
#pragma mark - Public
- (nullable instancetype)initWithEnv:(ORTEnv*)env
modelPath:(NSString*)path
sessionOptions:(nullable ORTSessionOptions*)sessionOptions
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
if (!sessionOptions) {
sessionOptions = [[ORTSessionOptions alloc] initWithError:error];
if (!sessionOptions) {
return nil;
}
}
_session = Ort::Session{[env CXXAPIOrtEnv],
path.UTF8String,
[sessionOptions CXXAPIOrtSessionOptions]};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputs:(NSDictionary<NSString*, ORTValue*>*)outputs
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error {
try {
if (!runOptions) {
runOptions = [[ORTRunOptions alloc] initWithError:error];
if (!runOptions) {
return NO;
}
}
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputs) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(static_cast<OrtValue*>([outputs[outputName] CXXAPIOrtValue]));
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions],
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (nullable NSDictionary<NSString*, ORTValue*>*)runWithInputs:(NSDictionary<NSString*, ORTValue*>*)inputs
outputNames:(NSSet<NSString*>*)outputNameSet
runOptions:(nullable ORTRunOptions*)runOptions
error:(NSError**)error {
try {
if (!runOptions) {
runOptions = [[ORTRunOptions alloc] initWithError:error];
if (!runOptions) {
return nil;
}
}
NSArray<NSString*>* outputNameArray = outputNameSet.allObjects;
std::vector<const char*> inputNames, outputNames;
std::vector<const OrtValue*> inputValues;
std::vector<OrtValue*> outputValues;
for (NSString* inputName in inputs) {
inputNames.push_back(inputName.UTF8String);
inputValues.push_back(static_cast<const OrtValue*>([inputs[inputName] CXXAPIOrtValue]));
}
for (NSString* outputName in outputNameArray) {
outputNames.push_back(outputName.UTF8String);
outputValues.push_back(nullptr);
}
Ort::ThrowOnError(Ort::GetApi().Run(*_session, [runOptions CXXAPIOrtRunOptions],
inputNames.data(), inputValues.data(), inputNames.size(),
outputNames.data(), outputNames.size(), outputValues.data()));
NSMutableDictionary<NSString*, ORTValue*>* outputs = [[NSMutableDictionary alloc] init];
for (NSUInteger i = 0; i < outputNameArray.count; ++i) {
ORTValue* outputValue = [[ORTValue alloc] initWithCAPIOrtValue:outputValues[i] externalTensorData:nil error:error];
if (!outputValue) {
// clean up remaining C API OrtValues which haven't been wrapped by an ORTValue yet
for (NSUInteger j = i; j < outputNameArray.count; ++j) {
Ort::GetApi().ReleaseValue(outputValues[j]);
}
return nil;
}
outputs[outputNameArray[i]] = outputValue;
}
return outputs;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable NSArray<NSString*>*)inputNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::Input error:error];
}
- (nullable NSArray<NSString*>*)overridableInitializerNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::OverridableInitializer error:error];
}
- (nullable NSArray<NSString*>*)outputNamesWithError:(NSError**)error {
return [self namesWithType:NamedValueType::Output error:error];
}
#pragma mark - Private
- (nullable NSArray<NSString*>*)namesWithType:(NamedValueType)namedValueType
error:(NSError**)error {
try {
auto getCount = [&session = *_session, namedValueType]() {
if (namedValueType == NamedValueType::Input) {
return session.GetInputCount();
} else if (namedValueType == NamedValueType::OverridableInitializer) {
return session.GetOverridableInitializerCount();
} else {
return session.GetOutputCount();
}
};
auto getName = [&session = *_session, namedValueType](size_t i, OrtAllocator* allocator) {
if (namedValueType == NamedValueType::Input) {
return session.GetInputNameAllocated(i, allocator);
} else if (namedValueType == NamedValueType::OverridableInitializer) {
return session.GetOverridableInitializerNameAllocated(i, allocator);
} else {
return session.GetOutputNameAllocated(i, allocator);
}
};
const size_t nameCount = getCount();
Ort::AllocatorWithDefaultOptions allocator;
NSMutableArray<NSString*>* result = [NSMutableArray arrayWithCapacity:nameCount];
for (size_t i = 0; i < nameCount; ++i) {
auto name = getName(i, allocator);
NSString* nameNsstr = [NSString stringWithUTF8String:name.get()];
NSAssert(nameNsstr != nil, @"nameNsstr must not be nil");
[result addObject:nameNsstr];
}
return result;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
@end
@implementation ORTSessionOptions {
std::optional<Ort::SessionOptions> _sessionOptions;
}
#pragma mark - Public
- (nullable instancetype)initWithError:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_sessionOptions = Ort::SessionOptions{};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)appendExecutionProvider:(NSString*)providerName
providerOptions:(NSDictionary<NSString*, NSString*>*)providerOptions
error:(NSError**)error {
try {
std::unordered_map<std::string, std::string> options;
NSArray* keys = [providerOptions allKeys];
for (NSString* key in keys) {
NSString* value = [providerOptions objectForKey:key];
options.emplace(key.UTF8String, value.UTF8String);
}
_sessionOptions->AppendExecutionProvider(providerName.UTF8String, options);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error);
}
- (BOOL)setIntraOpNumThreads:(int)intraOpNumThreads
error:(NSError**)error {
try {
_sessionOptions->SetIntraOpNumThreads(intraOpNumThreads);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setGraphOptimizationLevel:(ORTGraphOptimizationLevel)graphOptimizationLevel
error:(NSError**)error {
try {
_sessionOptions->SetGraphOptimizationLevel(
PublicToCAPIGraphOptimizationLevel(graphOptimizationLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setOptimizedModelFilePath:(NSString*)optimizedModelFilePath
error:(NSError**)error {
try {
_sessionOptions->SetOptimizedModelFilePath(optimizedModelFilePath.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogID:(NSString*)logID
error:(NSError**)error {
try {
_sessionOptions->SetLogId(logID.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
try {
_sessionOptions->SetLogSeverityLevel(PublicToCAPILoggingLevel(loggingLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error {
try {
_sessionOptions->AddConfigEntry(key.UTF8String, value.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)registerCustomOpsUsingFunction:(NSString*)registrationFuncName
error:(NSError**)error {
try {
_sessionOptions->RegisterCustomOpsUsingFunction(registrationFuncName.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
#pragma mark - Internal
- (Ort::SessionOptions&)CXXAPIOrtSessionOptions {
return *_sessionOptions;
}
@end
@implementation ORTRunOptions {
std::optional<Ort::RunOptions> _runOptions;
}
#pragma mark - Public
- (nullable instancetype)initWithError:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_runOptions = Ort::RunOptions{};
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (BOOL)setLogTag:(NSString*)logTag
error:(NSError**)error {
try {
_runOptions->SetRunTag(logTag.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)setLogSeverityLevel:(ORTLoggingLevel)loggingLevel
error:(NSError**)error {
try {
_runOptions->SetRunLogSeverityLevel(PublicToCAPILoggingLevel(loggingLevel));
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
- (BOOL)addConfigEntryWithKey:(NSString*)key
value:(NSString*)value
error:(NSError**)error {
try {
_runOptions->AddConfigEntry(key.UTF8String, value.UTF8String);
return YES;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_BOOL(error)
}
#pragma mark - Internal
- (Ort::RunOptions&)CXXAPIOrtRunOptions {
return *_runOptions;
}
@end
NS_ASSUME_NONNULL_END
+160
View File
@@ -0,0 +1,160 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import "ort_value_internal.h"
#include <optional>
#import "cxx_api.h"
#import "error_utils.h"
#import "ort_enums_internal.h"
NS_ASSUME_NONNULL_BEGIN
namespace {
ORTTensorTypeAndShapeInfo* CXXAPIToPublicTensorTypeAndShapeInfo(
const Ort::ConstTensorTypeAndShapeInfo& CXXAPITensorTypeAndShapeInfo) {
auto* result = [[ORTTensorTypeAndShapeInfo alloc] init];
const auto elementType = CXXAPITensorTypeAndShapeInfo.GetElementType();
const std::vector<int64_t> shape = CXXAPITensorTypeAndShapeInfo.GetShape();
result.elementType = CAPIToPublicTensorElementType(elementType);
auto* shapeArray = [[NSMutableArray alloc] initWithCapacity:shape.size()];
for (size_t i = 0; i < shape.size(); ++i) {
shapeArray[i] = @(shape[i]);
}
result.shape = shapeArray;
return result;
}
ORTValueTypeInfo* CXXAPIToPublicValueTypeInfo(
const Ort::TypeInfo& CXXAPITypeInfo) {
auto* result = [[ORTValueTypeInfo alloc] init];
const auto valueType = CXXAPITypeInfo.GetONNXType();
result.type = CAPIToPublicValueType(valueType);
if (valueType == ONNX_TYPE_TENSOR) {
const auto tensorTypeAndShapeInfo = CXXAPITypeInfo.GetTensorTypeAndShapeInfo();
result.tensorTypeAndShapeInfo = CXXAPIToPublicTensorTypeAndShapeInfo(tensorTypeAndShapeInfo);
}
return result;
}
// out = a * b
// returns true iff the result does not overflow
bool SafeMultiply(size_t a, size_t b, size_t& out) {
return !__builtin_mul_overflow(a, b, &out);
}
} // namespace
@interface ORTValue ()
// pointer to any external tensor data to keep alive for the lifetime of the ORTValue
@property(nonatomic, nullable) NSMutableData* externalTensorData;
@end
@implementation ORTValue {
std::optional<Ort::Value> _value;
std::optional<Ort::TypeInfo> _typeInfo;
}
#pragma mark - Public
- (nullable instancetype)initWithTensorData:(NSMutableData*)tensorData
elementType:(ORTTensorElementDataType)elementType
shape:(NSArray<NSNumber*>*)shape
error:(NSError**)error {
try {
const auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
const auto ONNXElementType = PublicToCAPITensorElementType(elementType);
const auto shapeVector = [shape]() {
std::vector<int64_t> result{};
result.reserve(shape.count);
for (NSNumber* dim in shape) {
result.push_back(dim.longLongValue);
}
return result;
}();
Ort::Value ortValue = Ort::Value::CreateTensor(
memoryInfo, tensorData.mutableBytes, tensorData.length,
shapeVector.data(), shapeVector.size(), ONNXElementType);
return [self initWithCAPIOrtValue:ortValue.release()
externalTensorData:tensorData
error:error];
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable ORTValueTypeInfo*)typeInfoWithError:(NSError**)error {
try {
return CXXAPIToPublicValueTypeInfo(*_typeInfo);
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable ORTTensorTypeAndShapeInfo*)tensorTypeAndShapeInfoWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
return CXXAPIToPublicTensorTypeAndShapeInfo(tensorTypeAndShapeInfo);
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
- (nullable NSMutableData*)tensorDataWithError:(NSError**)error {
try {
const auto tensorTypeAndShapeInfo = _typeInfo->GetTensorTypeAndShapeInfo();
const size_t elementCount = tensorTypeAndShapeInfo.GetElementCount();
const size_t elementSize = SizeOfCAPITensorElementType(tensorTypeAndShapeInfo.GetElementType());
size_t rawDataLength;
if (!SafeMultiply(elementCount, elementSize, rawDataLength)) {
ORT_CXX_API_THROW("failed to compute tensor data length", ORT_RUNTIME_EXCEPTION);
}
void* rawData;
Ort::ThrowOnError(Ort::GetApi().GetTensorMutableData(*_value, &rawData));
return [NSMutableData dataWithBytesNoCopy:rawData
length:rawDataLength
freeWhenDone:NO];
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error)
}
#pragma mark - Internal
- (nullable instancetype)initWithCAPIOrtValue:(OrtValue*)CAPIOrtValue
externalTensorData:(nullable NSMutableData*)externalTensorData
error:(NSError**)error {
if ((self = [super init]) == nil) {
return nil;
}
try {
_value = Ort::Value{CAPIOrtValue};
_typeInfo = _value->GetTypeInfo();
_externalTensorData = externalTensorData;
return self;
}
ORT_OBJC_API_IMPL_CATCH_RETURNING_NULLABLE(error);
}
- (Ort::Value&)CXXAPIOrtValue {
return *_value;
}
@end
@implementation ORTValueTypeInfo
@end
@implementation ORTTensorTypeAndShapeInfo
@end
NS_ASSUME_NONNULL_END
@@ -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
+4
View File
@@ -0,0 +1,4 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
static_assert(__has_feature(objc_arc), "Objective-C ARC must be enabled.");
+32
View File
@@ -0,0 +1,32 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
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
+30
View File
@@ -0,0 +1,30 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#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
+243
View File
@@ -0,0 +1,243 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#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 <vector>
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<NSNumber*>* 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<NSString*, ORTValue*>* 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<NSString*>* inputNames = [session inputNamesWithError:&err];
ORTAssertNullableResultSuccessful(inputNames, err);
XCTAssertEqualObjects(inputNames, (@[ @"A", @"B" ]));
NSArray<NSString*>* overridableInitializerNames = [session overridableInitializerNamesWithError:&err];
ORTAssertNullableResultSuccessful(overridableInitializerNames, err);
XCTAssertEqualObjects(overridableInitializerNames, (@[]));
NSArray<NSString*>* 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
+79
View File
@@ -0,0 +1,79 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#import <XCTest/XCTest.h>
#import "ort_value.h"
#include <vector>
#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<NSNumber*>* 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<int32_t> values{1, 2, 3, 4};
NSMutableData* data = [[NSMutableData alloc] initWithBytes:values.data()
length:values.size() * sizeof(int32_t)];
NSArray<NSNumber*>* 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
+12
View File
@@ -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 .
Binary file not shown.
Binary file not shown.
+19
View File
@@ -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")