add objectivec/test and objectivec/docs
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
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
|
||||||
|
# Specify the training header as umbrella_header so that every public header is included.
|
||||||
|
# The training header is a superset of the inference-only header.
|
||||||
|
umbrella_header: ../include/onnxruntime_training.h
|
||||||
|
framework_root: ..
|
||||||
|
|
||||||
|
readme: ./main_page.md
|
||||||
|
|
||||||
|
hide_documentation_coverage: true
|
||||||
|
undocumented_text: ""
|
||||||
@@ -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.
|
||||||
@@ -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.
|
||||||
@@ -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.");
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
#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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,326 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (NSString*)getStringModelPath {
|
||||||
|
NSBundle* bundle = [NSBundle bundleForClass:[ORTSessionTest class]];
|
||||||
|
NSString* path = [bundle pathForResource:@"identity_string"
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testStringInputs {
|
||||||
|
NSError* err = nil;
|
||||||
|
NSArray<NSString*>* stringData = @[ @"ONNX Runtime", @"is the", @"best", @"AI Framework" ];
|
||||||
|
ORTValue* stringValue = [[ORTValue alloc] initWithTensorStringData:stringData shape:@[ @2, @2 ] error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(stringValue, err);
|
||||||
|
|
||||||
|
ORTSession* session = [[ORTSession alloc] initWithEnv:self.ortEnv
|
||||||
|
modelPath:[ORTSessionTest getStringModelPath]
|
||||||
|
sessionOptions:[ORTSessionTest makeSessionOptions]
|
||||||
|
error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(session, err);
|
||||||
|
|
||||||
|
NSDictionary<NSString*, ORTValue*>* outputs =
|
||||||
|
[session runWithInputs:@{@"input:0" : stringValue}
|
||||||
|
outputNames:[NSSet setWithArray:@[ @"output:0" ]]
|
||||||
|
runOptions:[ORTSessionTest makeRunOptions]
|
||||||
|
error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(outputs, err);
|
||||||
|
|
||||||
|
ORTValue* outputStringValue = outputs[@"output:0"];
|
||||||
|
XCTAssertNotNil(outputStringValue);
|
||||||
|
|
||||||
|
NSArray<NSString*>* outputStringData = [outputStringValue tensorStringDataWithError:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(outputStringData, err);
|
||||||
|
|
||||||
|
XCTAssertEqual([stringData count], [outputStringData count]);
|
||||||
|
XCTAssertTrue([stringData isEqualToArray:outputStringData]);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testKeepORTEnvReference {
|
||||||
|
ORTEnv* __weak envWeak = _ortEnv;
|
||||||
|
// Remove sole strong reference to the ORTEnv created in setUp.
|
||||||
|
_ortEnv = nil;
|
||||||
|
// There should be no more strong references to it.
|
||||||
|
XCTAssertNil(envWeak);
|
||||||
|
|
||||||
|
// Create a new ORTEnv.
|
||||||
|
NSError* err = nil;
|
||||||
|
ORTEnv* env = [[ORTEnv alloc] initWithLoggingLevel:ORTLoggingLevelWarning
|
||||||
|
error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(env, err);
|
||||||
|
|
||||||
|
ORTSession* session = [[ORTSession alloc] initWithEnv:env
|
||||||
|
modelPath:[ORTSessionTest getAddModelPath]
|
||||||
|
sessionOptions:[ORTSessionTest makeSessionOptions]
|
||||||
|
error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(session, err);
|
||||||
|
|
||||||
|
envWeak = env;
|
||||||
|
// Remove strong reference to the ORTEnv passed to the ORTSession initializer.
|
||||||
|
env = nil;
|
||||||
|
// ORTSession should keep a strong reference to it.
|
||||||
|
XCTAssertNotNil(envWeak);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
#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<NSString*>* lines = [fileContents componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]];
|
||||||
|
|
||||||
|
if (skipHeader) {
|
||||||
|
lines = [lines subarrayWithRange:NSMakeRange(1, lines.count - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
NSArray<NSString*>* 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<NSString*>* 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<NSString*>* 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<NSString*>* 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<NSString*>* 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<ORTValue*>* 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<ORTValue*>* 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<ORTValue*>* 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<ORTValue*>* 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<NSString*>* 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
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
#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
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)testInitTensorWithStringDataSucceeds {
|
||||||
|
NSArray<NSString*>* stringData = @[ @"ONNX Runtime", @"is", @"the", @"best", @"AI", @"Framework" ];
|
||||||
|
NSError* err = nil;
|
||||||
|
ORTValue* stringValue = [[ORTValue alloc] initWithTensorStringData:stringData shape:@[ @3, @2 ] error:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(stringValue, err);
|
||||||
|
|
||||||
|
NSArray<NSString*>* returnedStringData = [stringValue tensorStringDataWithError:&err];
|
||||||
|
ORTAssertNullableResultSuccessful(returnedStringData, err);
|
||||||
|
|
||||||
|
XCTAssertEqual([stringData count], [returnedStringData count]);
|
||||||
|
XCTAssertTrue([stringData isEqualToArray:returnedStringData]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <XCTest/XCTest.h>
|
||||||
|
|
||||||
|
#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<NSNumber*>* getFloatArrayFromData(NSData* data);
|
||||||
|
|
||||||
|
} // namespace test_utils
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -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<NSNumber*>* getFloatArrayFromData(NSData* data) {
|
||||||
|
NSMutableArray<NSNumber*>* 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
|
||||||
+12
@@ -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 .
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
+19
@@ -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")
|
||||||
Reference in New Issue
Block a user