Skip to content

Commit b5d8e3b

Browse files
authored
Move ExecutorchRuntimeValueSupport and ExecutorchRuntimeBridge to xplat
Differential Revision: D70825991 Pull Request resolved: pytorch#9244
1 parent e9cf64a commit b5d8e3b

File tree

10 files changed

+567
-0
lines changed

10 files changed

+567
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#ifdef __cplusplus
4+
#import <executorch/extension/module/module.h>
5+
#import <executorch/runtime/core/evalue.h>
6+
#endif
7+
#import <ModelRunnerDataKit/ModelRunnerDataKit-Swift.h>
8+
9+
NS_ASSUME_NONNULL_BEGIN
10+
11+
@interface ExecutorchRuntimeTensorValue : NSObject <ModelRuntimeTensorValueBridging>
12+
13+
- (instancetype)init NS_UNAVAILABLE;
14+
+ (instancetype)new NS_UNAVAILABLE;
15+
16+
- (instancetype)initWithFloatArray:(NSArray<NSNumber *> *)floatArray shape:(NSArray<NSNumber *> *)sizes NS_SWIFT_NAME(init(floatArray:shape:));
17+
18+
#ifdef __cplusplus
19+
- (nullable instancetype)initWithTensor:(torch::executor::Tensor)tensor error:(NSError * _Nullable * _Nullable)error;
20+
- (instancetype)initWithData:(std::vector<float>)floatData
21+
shape:(std::vector<int32_t>)shape NS_DESIGNATED_INITIALIZER;
22+
- (torch::executor::Tensor)backedValue;
23+
#endif
24+
25+
@end
26+
27+
NS_ASSUME_NONNULL_END
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#import "ExecutorchRuntimeTensorValue.h"
4+
5+
#import <memory>
6+
7+
#import <executorch/extension/module/module.h>
8+
9+
using torch::executor::TensorImpl;
10+
using torch::executor::ScalarType;
11+
12+
@implementation ExecutorchRuntimeTensorValue
13+
{
14+
std::unique_ptr<TensorImpl> _tensor;
15+
// TensorImpl DOES NOT take ownership.
16+
// This float vector is what keeps the data in memory.
17+
std::vector<float> _floatData;
18+
std::vector<int32_t> _shape;
19+
}
20+
21+
- (instancetype)initWithData:(std::vector<float>)floatData
22+
shape:(std::vector<int32_t>)shape
23+
{
24+
if (self = [super init]) {
25+
_floatData.assign(floatData.begin(), floatData.end());
26+
_shape.assign(shape.begin(), shape.end());
27+
_tensor = std::make_unique<TensorImpl>(ScalarType::Float, std::size(_shape), _shape.data(), _floatData.data());
28+
}
29+
return self;
30+
}
31+
32+
- (instancetype)initWithFloatArray:(NSArray<NSNumber *> *)floatArray shape:(NSArray<NSNumber *> *)shape
33+
{
34+
std::vector<float> floatVector;
35+
std::vector<int32_t> shapeVector;
36+
37+
floatVector.reserve(floatArray.count);
38+
for (int i = 0; i < floatArray.count; i++) {
39+
floatVector.push_back([floatArray[i] floatValue]);
40+
}
41+
shapeVector.reserve(shape.count);
42+
for (int i = 0; i < shape.count; i++) {
43+
shapeVector.push_back([shape[i] intValue]);
44+
}
45+
46+
return [self initWithData:floatVector shape:shapeVector];
47+
}
48+
49+
- (nullable instancetype)initWithTensor:(torch::executor::Tensor)tensor error:(NSError * _Nullable * _Nullable)error
50+
{
51+
if (tensor.scalar_type() != ScalarType::Float) {
52+
if (error) {
53+
*error = [ModelRuntimeValueErrorFactory invalidType:[NSString stringWithFormat:@"torch::executor::ScalarType::%hhd", tensor.scalar_type()] expectedType:@"torch::executor::ScalarType::Float"];
54+
}
55+
return nil;
56+
}
57+
58+
std::vector<float> floatVector;
59+
std::vector<int32_t> shapeVector;
60+
shapeVector.assign(tensor.sizes().begin(), tensor.sizes().end());
61+
floatVector.assign(tensor.const_data_ptr<float>(), tensor.const_data_ptr<float>() + tensor.numel());
62+
return [self initWithData:floatVector shape:shapeVector];
63+
}
64+
65+
- (nullable ModelRuntimeTensorValueBridgingTuple *)floatRepresentationAndReturnError:(NSError * _Nullable * _Nullable)error
66+
{
67+
if (_tensor->scalar_type() == torch::executor::ScalarType::Float) {
68+
const auto *tensorPtr = _tensor->data<float>();
69+
const auto sizes = _tensor->sizes();
70+
std::vector<float> tensorVec(tensorPtr, tensorPtr + _tensor->numel());
71+
std::vector<int32_t> tensorSizes(sizes.begin(), sizes.end());
72+
73+
NSMutableArray<NSNumber *> *floatArray = [[NSMutableArray alloc] initWithCapacity:tensorVec.size()];
74+
for (float &i : tensorVec) {
75+
[floatArray addObject:@(i)];
76+
}
77+
78+
NSMutableArray<NSNumber *> *sizesArray = [[NSMutableArray alloc] initWithCapacity:tensorSizes.size()];
79+
for (int &tensorSize : tensorSizes) {
80+
[sizesArray addObject:@(tensorSize)];
81+
}
82+
83+
return [[ModelRuntimeTensorValueBridgingTuple alloc] initWithFloatArray:floatArray shape:sizesArray];
84+
}
85+
86+
if (error) {
87+
*error = [ModelRuntimeValueErrorFactory
88+
invalidType:[NSString stringWithFormat:@"torch::executor::ScalarType::%hhd", _tensor->scalar_type()]
89+
expectedType:@"torch::executor::ScalarType::Float"];
90+
}
91+
92+
return nil;
93+
}
94+
95+
- (torch::executor::Tensor)backedValue
96+
{
97+
return torch::executor::Tensor(_tensor.get());
98+
}
99+
100+
@end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#ifdef __cplusplus
4+
#import <executorch/extension/module/module.h>
5+
#import <executorch/runtime/core/evalue.h>
6+
#endif
7+
8+
#import <ModelRunnerDataKit/ModelRunnerDataKit-Swift.h>
9+
10+
#import "ExecutorchRuntimeTensorValue.h"
11+
12+
NS_ASSUME_NONNULL_BEGIN
13+
14+
@interface ExecutorchRuntimeValue : NSObject <ModelRuntimeValueBridging>
15+
16+
- (instancetype)init NS_UNAVAILABLE;
17+
+ (instancetype)new NS_UNAVAILABLE;
18+
19+
- (instancetype)initWithTensor:(ExecutorchRuntimeTensorValue *)tensorValue;
20+
21+
#ifdef __cplusplus
22+
- (instancetype)initWithEValue:(torch::executor::EValue)value NS_DESIGNATED_INITIALIZER;
23+
- (torch::executor::EValue)getBackedValue;
24+
#endif
25+
26+
@end
27+
28+
NS_ASSUME_NONNULL_END
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#import "ExecutorchRuntimeValue.h"
4+
5+
#import <map>
6+
#import <vector>
7+
8+
#import "ExecutorchRuntimeTensorValue.h"
9+
10+
using torch::executor::EValue;
11+
12+
@implementation ExecutorchRuntimeValue
13+
{
14+
EValue _value;
15+
// IMPORTANT
16+
// Tensor value keeps a reference to the original tensor value. However, the value that is wrapped by LiteInterpreterRuntimeTensorValue DOES NOT TAKE OWNERSHIP OF THE RAW DATA!
17+
// This means once the wrapper is deallocated, the tensor value will be deallocated as well.
18+
// This reference here is to keep the tensor value alive until the runtime is deallocated.
19+
ExecutorchRuntimeTensorValue *_tensorValue;
20+
}
21+
22+
- (instancetype)initWithEValue:(EValue)value
23+
{
24+
if (self = [super init]) {
25+
_value = value;
26+
}
27+
return self;
28+
}
29+
30+
- (instancetype)initWithTensor:(ExecutorchRuntimeTensorValue *)tensorValue
31+
{
32+
if (self = [self initWithEValue:EValue([tensorValue backedValue])]) {
33+
_tensorValue = tensorValue;
34+
}
35+
return self;
36+
}
37+
38+
- (nullable NSString *)stringValueAndReturnError:(NSError * _Nullable * _Nullable)error
39+
{
40+
if (error) {
41+
*error = [ModelRuntimeValueErrorFactory unsupportedType:@"ExecutorchRuntimeValue doesn't support strings"];
42+
}
43+
return nil;
44+
}
45+
46+
- (nullable id<ModelRuntimeTensorValueBridging>)tensorValueAndReturnError:(NSError * _Nullable * _Nullable)error
47+
{
48+
if (_value.isTensor()) {
49+
return [[ExecutorchRuntimeTensorValue alloc] initWithTensor:_value.toTensor() error:error];
50+
}
51+
52+
if (error) {
53+
*error = [ModelRuntimeValueErrorFactory
54+
invalidType:[NSString stringWithFormat:@"Tag::%d", _value.tag]
55+
expectedType:@"Tag::Tensor"];
56+
}
57+
return nil;
58+
}
59+
60+
- (EValue)getBackedValue
61+
{
62+
return _value;
63+
}
64+
65+
- (NSArray<id<ModelRuntimeValueBridging>> *)arrayValueAndReturnError:(NSError * _Nullable * _Nullable)error
66+
{
67+
if (error) {
68+
*error = [ModelRuntimeValueErrorFactory unsupportedType:@"EValue doesn't support arrays"];
69+
}
70+
return nil;
71+
}
72+
73+
@end
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#import <Foundation/Foundation.h>
4+
5+
#import "ExecutorchRuntimeValue.h"
6+
7+
NS_ASSUME_NONNULL_BEGIN
8+
9+
@interface ExecutorchRuntimeEngine : NSObject
10+
11+
- (nonnull instancetype)init NS_UNAVAILABLE;
12+
+ (nonnull instancetype)new NS_UNAVAILABLE;
13+
14+
- (nullable instancetype)initWithModelPath:(NSString *)modelPath
15+
modelMethodName:(NSString *)modelMethodName
16+
error:(NSError * _Nullable * _Nullable)error NS_DESIGNATED_INITIALIZER;
17+
18+
- (nullable NSArray<ExecutorchRuntimeValue *> *)infer:(NSArray<ExecutorchRuntimeValue *> *)input
19+
error:(NSError * _Nullable * _Nullable)error NS_SWIFT_NAME(infer(input:));
20+
21+
@end
22+
23+
NS_ASSUME_NONNULL_END
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
#import "ExecutorchRuntimeEngine.h"
4+
5+
#import <map>
6+
#import <vector>
7+
8+
#import <executorch/extension/module/module.h>
9+
10+
static int kInitFailed = 0;
11+
static int kInferenceFailed = 1;
12+
13+
static auto NSStringToString(NSString *string) -> std::string
14+
{
15+
const char *cStr = [string cStringUsingEncoding:NSUTF8StringEncoding];
16+
if (cStr) {
17+
return cStr;
18+
}
19+
20+
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
21+
return {reinterpret_cast<const char *>([data bytes]), [data length]};
22+
}
23+
24+
static auto StringToNSString(const std::string &string) -> NSString *
25+
{
26+
CFStringRef cfString = CFStringCreateWithBytes(
27+
kCFAllocatorDefault,
28+
reinterpret_cast<const UInt8 *>(string.c_str()),
29+
string.size(),
30+
kCFStringEncodingUTF8,
31+
false
32+
);
33+
return (__bridge_transfer NSString *)cfString;
34+
}
35+
36+
@implementation ExecutorchRuntimeEngine
37+
{
38+
NSString *_modelPath;
39+
NSString *_modelMethodName;
40+
std::unique_ptr<torch::executor::Module> _module;
41+
}
42+
43+
- (instancetype)initWithModelPath:(NSString *)modelPath
44+
modelMethodName:(NSString *)modelMethodName
45+
error:(NSError * _Nullable * _Nullable)error
46+
{
47+
if (self = [super init]) {
48+
_modelPath = modelPath;
49+
_modelMethodName = modelMethodName;
50+
try {
51+
_module = std::make_unique<torch::executor::Module>(NSStringToString(modelPath));
52+
const auto e = _module->load_method(NSStringToString(modelMethodName));
53+
if (e != executorch::runtime::Error::Ok) {
54+
if (error) {
55+
*error = [NSError errorWithDomain:@"ExecutorchRuntimeEngine"
56+
code:kInitFailed
57+
userInfo:@{NSDebugDescriptionErrorKey : StringToNSString(std::to_string(static_cast<uint32_t>(e)))}];
58+
}
59+
return nil;
60+
}
61+
} catch (...) {
62+
if (error) {
63+
*error = [NSError errorWithDomain:@"ExecutorchRuntimeEngine"
64+
code:kInitFailed
65+
userInfo:@{NSDebugDescriptionErrorKey : @"Unknown error"}];
66+
}
67+
return nil;
68+
}
69+
}
70+
return self;
71+
}
72+
73+
- (nullable NSArray<ExecutorchRuntimeValue *> *)infer:(NSArray<ExecutorchRuntimeValue *> *)input
74+
error:(NSError * _Nullable * _Nullable)error
75+
{
76+
try {
77+
std::vector<torch::executor::EValue> inputEValues;
78+
inputEValues.reserve(input.count);
79+
for (ExecutorchRuntimeValue *inputValue in input) {
80+
inputEValues.push_back([inputValue getBackedValue]);
81+
}
82+
const auto result = _module->execute(NSStringToString(_modelMethodName), inputEValues);
83+
if (!result.ok()) {
84+
const auto executorchError = static_cast<uint32_t>(result.error());
85+
if (error) {
86+
*error = [NSError errorWithDomain:@"ExecutorchRuntimeEngine"
87+
code:kInferenceFailed
88+
userInfo:@{NSDebugDescriptionErrorKey : StringToNSString(std::to_string(executorchError))}];
89+
}
90+
return nil;
91+
}
92+
NSMutableArray<ExecutorchRuntimeValue *> *const resultValues = [NSMutableArray new];
93+
for (const auto &evalue : result.get()) {
94+
[resultValues addObject:[[ExecutorchRuntimeValue alloc] initWithEValue:evalue]];
95+
}
96+
return resultValues;
97+
} catch (...) {
98+
if (error) {
99+
*error = [NSError errorWithDomain:@"LiteInterpreterRuntimeEngine"
100+
code:kInferenceFailed
101+
userInfo:@{NSDebugDescriptionErrorKey : @"Unknown error"}];
102+
}
103+
return nil;
104+
}
105+
}
106+
107+
@end

0 commit comments

Comments
 (0)