mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-15 20:50:42 +00:00
**Description**: Use full ORT package for onnxruntime-react-native. Left the params required for the mobile build in comments so they're easily discovered if we need to create onnxruntime-react-native-mobile in the future. **Motivation and Context** Remove barrier to using ORT with react native as the mobile package that was being used supports a limited range of opsets/operators/types, and requires ORT format models. The full package will run any model.
246 lines
11 KiB
Text
246 lines
11 KiB
Text
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
#import "TensorHelper.h"
|
|
|
|
#import <XCTest/XCTest.h>
|
|
#import <onnxruntime/onnxruntime_cxx_api.h>
|
|
#include <vector>
|
|
|
|
@interface TensorHelperTest : XCTestCase
|
|
|
|
@end
|
|
|
|
@implementation TensorHelperTest
|
|
|
|
template <typename T>
|
|
static void testCreateInputTensorT(const std::array<T, 3> &outValues, std::function<NSNumber *(T value)> &convert,
|
|
ONNXTensorElementDataType onnxType, NSString *jsTensorType) {
|
|
NSMutableDictionary *inputTensorMap = [NSMutableDictionary dictionary];
|
|
|
|
// dims
|
|
NSArray *dims = @[ [NSNumber numberWithLong:outValues.size()] ];
|
|
inputTensorMap[@"dims"] = dims;
|
|
|
|
// type
|
|
inputTensorMap[@"type"] = jsTensorType;
|
|
|
|
// encoded data
|
|
size_t byteBufferSize = sizeof(T) * outValues.size();
|
|
unsigned char *byteBuffer = static_cast<unsigned char *>(malloc(byteBufferSize));
|
|
NSData *byteBufferRef = [NSData dataWithBytesNoCopy:byteBuffer length:byteBufferSize];
|
|
T *typePtr = (T *)[byteBufferRef bytes];
|
|
for (size_t i = 0; i < outValues.size(); ++i) {
|
|
typePtr[i] = outValues[i];
|
|
}
|
|
|
|
NSString *dataEncoded = [byteBufferRef base64EncodedStringWithOptions:0];
|
|
inputTensorMap[@"data"] = dataEncoded;
|
|
|
|
Ort::AllocatorWithDefaultOptions ortAllocator;
|
|
std::vector<Ort::MemoryAllocation> allocations;
|
|
Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap
|
|
ortAllocator:ortAllocator
|
|
allocations:allocations];
|
|
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetElementType(), onnxType);
|
|
XCTAssertTrue(inputTensor.IsTensor());
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetDimensionsCount(), 1);
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetShape(),
|
|
std::vector<int64_t>{static_cast<int64_t>(outValues.size())});
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetElementCount(), outValues.size());
|
|
const auto tensorData = inputTensor.GetTensorData<T>();
|
|
for (size_t i = 0; i < outValues.size(); ++i) {
|
|
XCTAssertEqual(tensorData[i], outValues[i]);
|
|
}
|
|
}
|
|
|
|
- (void)testCreateInputTensorFloat {
|
|
std::array<float_t, 3> outValues{std::numeric_limits<float_t>::min(), 2.0f, std::numeric_limits<float_t>::max()};
|
|
std::function<NSNumber *(float_t value)> convert = [](float_t value) { return [NSNumber numberWithFloat:value]; };
|
|
testCreateInputTensorT<float_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, JsTensorTypeFloat);
|
|
}
|
|
|
|
- (void)testCreateInputTensorDouble {
|
|
std::array<double_t, 3> outValues{std::numeric_limits<double_t>::min(), 2.0f, std::numeric_limits<double_t>::max()};
|
|
std::function<NSNumber *(double_t value)> convert = [](double_t value) { return [NSNumber numberWithDouble:value]; };
|
|
testCreateInputTensorT<double_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_DOUBLE, JsTensorTypeDouble);
|
|
}
|
|
|
|
- (void)testCreateInputTensorBool {
|
|
std::array<bool, 3> outValues{false, true, true};
|
|
std::function<NSNumber *(bool value)> convert = [](bool value) { return [NSNumber numberWithBool:value]; };
|
|
testCreateInputTensorT<bool>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_BOOL, JsTensorTypeBool);
|
|
}
|
|
|
|
- (void)testCreateInputTensorInt8 {
|
|
std::array<int8_t, 3> outValues{std::numeric_limits<int8_t>::min(), 2, std::numeric_limits<int8_t>::max()};
|
|
std::function<NSNumber *(int8_t value)> convert = [](int8_t value) { return [NSNumber numberWithChar:value]; };
|
|
testCreateInputTensorT<int8_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT8, JsTensorTypeByte);
|
|
}
|
|
|
|
- (void)testCreateInputTensorInt16 {
|
|
std::array<int16_t, 3> outValues{std::numeric_limits<int16_t>::min(), 2, std::numeric_limits<int16_t>::max()};
|
|
std::function<NSNumber *(int16_t value)> convert = [](int16_t value) { return [NSNumber numberWithShort:value]; };
|
|
testCreateInputTensorT<int16_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT16, JsTensorTypeShort);
|
|
}
|
|
|
|
- (void)testCreateInputTensorInt32 {
|
|
std::array<int32_t, 3> outValues{std::numeric_limits<int32_t>::min(), 2, std::numeric_limits<int32_t>::max()};
|
|
std::function<NSNumber *(int32_t value)> convert = [](int32_t value) { return [NSNumber numberWithInt:value]; };
|
|
testCreateInputTensorT<int32_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT32, JsTensorTypeInt);
|
|
}
|
|
|
|
- (void)testCreateInputTensorInt64 {
|
|
std::array<int64_t, 3> outValues{std::numeric_limits<int64_t>::min(), 2, std::numeric_limits<int64_t>::max()};
|
|
std::function<NSNumber *(int64_t value)> convert = [](int64_t value) { return [NSNumber numberWithLongLong:value]; };
|
|
testCreateInputTensorT<int64_t>(outValues, convert, ONNX_TENSOR_ELEMENT_DATA_TYPE_INT64, JsTensorTypeLong);
|
|
}
|
|
|
|
- (void)testCreateInputTensorString {
|
|
std::array<std::string, 3> outValues{"a", "b", "c"};
|
|
|
|
NSMutableDictionary *inputTensorMap = [NSMutableDictionary dictionary];
|
|
|
|
// dims
|
|
NSArray *dims = @[ [NSNumber numberWithLong:outValues.size()] ];
|
|
inputTensorMap[@"dims"] = dims;
|
|
|
|
// type
|
|
inputTensorMap[@"type"] = JsTensorTypeString;
|
|
|
|
// data
|
|
NSMutableArray *data = [NSMutableArray array];
|
|
for (auto value : outValues) {
|
|
[data addObject:[NSString stringWithUTF8String:value.c_str()]];
|
|
}
|
|
inputTensorMap[@"data"] = data;
|
|
|
|
Ort::AllocatorWithDefaultOptions ortAllocator;
|
|
std::vector<Ort::MemoryAllocation> allocations;
|
|
Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap
|
|
ortAllocator:ortAllocator
|
|
allocations:allocations];
|
|
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetElementType(), ONNX_TENSOR_ELEMENT_DATA_TYPE_STRING);
|
|
XCTAssertTrue(inputTensor.IsTensor());
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetDimensionsCount(), 1);
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetShape(),
|
|
std::vector<int64_t>{static_cast<int64_t>(outValues.size())});
|
|
XCTAssertEqual(inputTensor.GetTensorTypeAndShapeInfo().GetElementCount(), outValues.size());
|
|
for (int i = 0; i < inputTensor.GetTensorTypeAndShapeInfo().GetElementCount(); ++i) {
|
|
size_t elementLength = inputTensor.GetStringTensorElementLength(i);
|
|
std::string element(elementLength, '\0');
|
|
inputTensor.GetStringTensorElement(elementLength, i, (void *)element.data());
|
|
XCTAssertEqual(element, outValues[i]);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
static void testCreateOutputTensorT(const std::array<T, 5> &outValues, std::function<NSNumber *(T value)> &convert,
|
|
NSString *jsTensorType, NSString *testDataFileName,
|
|
NSString *testDataFileExtension) {
|
|
NSBundle *bundle = [NSBundle bundleForClass:[TensorHelperTest class]];
|
|
NSString *dataPath = [bundle pathForResource:testDataFileName ofType:testDataFileExtension];
|
|
|
|
Ort::Env ortEnv{ORT_LOGGING_LEVEL_INFO, "Default"};
|
|
Ort::SessionOptions sessionOptions;
|
|
Ort::Session session{ortEnv, [dataPath UTF8String], sessionOptions};
|
|
|
|
Ort::AllocatorWithDefaultOptions ortAllocator;
|
|
std::vector<Ort::AllocatedStringPtr> names;
|
|
|
|
names.reserve(session.GetInputCount() + session.GetOutputCount());
|
|
|
|
std::vector<const char *> inputNames;
|
|
inputNames.reserve(session.GetInputCount());
|
|
for (size_t i = 0; i < session.GetInputCount(); ++i) {
|
|
auto inputName = session.GetInputNameAllocated(i, ortAllocator);
|
|
inputNames.emplace_back(inputName.get());
|
|
names.emplace_back(std::move(inputName));
|
|
}
|
|
|
|
std::vector<const char *> outputNames;
|
|
outputNames.reserve(session.GetOutputCount());
|
|
for (size_t i = 0; i < session.GetOutputCount(); ++i) {
|
|
auto outputName = session.GetOutputNameAllocated(i, ortAllocator);
|
|
outputNames.emplace_back(outputName.get());
|
|
names.emplace_back(std::move(outputName));
|
|
}
|
|
|
|
NSMutableDictionary *inputTensorMap = [NSMutableDictionary dictionary];
|
|
|
|
// dims
|
|
NSArray *dims = @[ [NSNumber numberWithLong:1], [NSNumber numberWithLong:outValues.size()] ];
|
|
inputTensorMap[@"dims"] = dims;
|
|
|
|
// type
|
|
inputTensorMap[@"type"] = jsTensorType;
|
|
|
|
// encoded data
|
|
size_t byteBufferSize = sizeof(T) * outValues.size();
|
|
unsigned char *byteBuffer = static_cast<unsigned char *>(malloc(byteBufferSize));
|
|
NSData *byteBufferRef = [NSData dataWithBytesNoCopy:byteBuffer length:byteBufferSize];
|
|
T *typePtr = (T *)[byteBufferRef bytes];
|
|
for (size_t i = 0; i < outValues.size(); ++i) {
|
|
typePtr[i] = outValues[i];
|
|
}
|
|
|
|
NSString *dataEncoded = [byteBufferRef base64EncodedStringWithOptions:0];
|
|
inputTensorMap[@"data"] = dataEncoded;
|
|
std::vector<Ort::MemoryAllocation> allocations;
|
|
Ort::Value inputTensor = [TensorHelper createInputTensor:inputTensorMap
|
|
ortAllocator:ortAllocator
|
|
allocations:allocations];
|
|
|
|
std::vector<Ort::Value> feeds;
|
|
feeds.emplace_back(std::move(inputTensor));
|
|
|
|
Ort::RunOptions runOptions;
|
|
auto output = session.Run(runOptions, inputNames.data(), feeds.data(), inputNames.size(), outputNames.data(),
|
|
outputNames.size());
|
|
|
|
NSDictionary *resultMap = [TensorHelper createOutputTensor:outputNames values:output];
|
|
|
|
XCTAssertTrue([[resultMap objectForKey:@"output"] isEqualToDictionary:inputTensorMap]);
|
|
}
|
|
|
|
- (void)testCreateOutputTensorFloat {
|
|
std::array<float_t, 5> outValues{std::numeric_limits<float_t>::min(), 1.0f, 2.0f, 3.0f,
|
|
std::numeric_limits<float_t>::max()};
|
|
std::function<NSNumber *(float_t value)> convert = [](float_t value) { return [NSNumber numberWithFloat:value]; };
|
|
testCreateOutputTensorT<float_t>(outValues, convert, JsTensorTypeFloat, @"test_types_float", @"ort");
|
|
}
|
|
|
|
- (void)testCreateOutputTensorDouble {
|
|
std::array<double_t, 5> outValues{std::numeric_limits<double_t>::min(), 1.0f, 2.0f, 3.0f,
|
|
std::numeric_limits<double_t>::max()};
|
|
std::function<NSNumber *(double_t value)> convert = [](double_t value) { return [NSNumber numberWithDouble:value]; };
|
|
testCreateOutputTensorT<double_t>(outValues, convert, JsTensorTypeDouble, @"test_types_double", @"onnx");
|
|
}
|
|
|
|
- (void)testCreateOutputTensorBool {
|
|
std::array<bool, 5> outValues{false, true, true, false, true};
|
|
std::function<NSNumber *(bool value)> convert = [](bool value) { return [NSNumber numberWithBool:value]; };
|
|
testCreateOutputTensorT<bool>(outValues, convert, JsTensorTypeBool, @"test_types_bool", @"onnx");
|
|
}
|
|
|
|
- (void)testCreateOutputTensorInt8 {
|
|
std::array<int8_t, 5> outValues{std::numeric_limits<int8_t>::min(), 1, -2, 3, std::numeric_limits<int8_t>::max()};
|
|
std::function<NSNumber *(int8_t value)> convert = [](int8_t value) { return [NSNumber numberWithChar:value]; };
|
|
testCreateOutputTensorT<int8_t>(outValues, convert, JsTensorTypeByte, @"test_types_int8", @"ort");
|
|
}
|
|
|
|
- (void)testCreateOutputTensorInt32 {
|
|
std::array<int32_t, 5> outValues{std::numeric_limits<int32_t>::min(), 1, -2, 3, std::numeric_limits<int32_t>::max()};
|
|
std::function<NSNumber *(int32_t value)> convert = [](int32_t value) { return [NSNumber numberWithInt:value]; };
|
|
testCreateOutputTensorT<int32_t>(outValues, convert, JsTensorTypeInt, @"test_types_int32", @"ort");
|
|
}
|
|
|
|
- (void)testCreateOutputTensorInt64 {
|
|
std::array<int64_t, 5> outValues{std::numeric_limits<int64_t>::min(), 1, -2, 3, std::numeric_limits<int64_t>::max()};
|
|
std::function<NSNumber *(int64_t value)> convert = [](int64_t value) { return [NSNumber numberWithLongLong:value]; };
|
|
testCreateOutputTensorT<int64_t>(outValues, convert, JsTensorTypeLong, @"test_types_int64", @"ort");
|
|
}
|
|
|
|
@end
|