chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,112 @@
// Copyright 2020 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef COCOAPODS
@import TFLTensorFlowLite;
#else
#import "tensorflow/lite/objc/apis/TFLCoreMLDelegate.h"
#import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h"
#endif
#import <XCTest/XCTest.h>
NS_ASSUME_NONNULL_BEGIN
/** Float model resource name.
* The model has a graph equivalent to (input + input) + input.
*/
static NSString* const kAddFloatModelResourceName = @"add";
/** Model resource type. */
static NSString* const kAddModelResourceType = @"bin";
/**
* @var kTensorSize
* Size of input and output tensors
* @var kTensorChannels
* Size of channel dimension of input and output tensors
*/
enum EnumType : int {kTensorSize = 8 * 8 * 3, kTensorChannels = 3};
/** Accuracy used in comparing floating numbers. */
static const float kTestAccuracy = 1E-5F;
@interface TFLCoreMLDelegateTests : XCTestCase
@end
@implementation TFLCoreMLDelegateTests
- (void)testCoreMLDelegate {
if (@available(iOS 11.0, *)) {
} else {
return;
}
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* floatModelPath = [bundle pathForResource:kAddFloatModelResourceName
ofType:kAddModelResourceType];
TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init];
TFLCoreMLDelegateOptions* coreMLOptions = [[TFLCoreMLDelegateOptions alloc] init];
coreMLOptions.enabledDevices = TFLCoreMLDelegateEnabledDevicesAll;
TFLCoreMLDelegate* coreMLDelegate = [[TFLCoreMLDelegate alloc] initWithOptions:coreMLOptions];
XCTAssertNotNil(coreMLDelegate);
NSError* error;
TFLInterpreter* interpreter = [[TFLInterpreter alloc] initWithModelPath:floatModelPath
options:options
delegates:@[ coreMLDelegate ]
error:&error];
XCTAssertNil(error);
XCTAssertNotNil(interpreter);
XCTAssertTrue([interpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Copies the input data.
NSMutableData* inputData = [NSMutableData dataWithLength:sizeof(float) * kTensorSize];
for (int i = 0; i < kTensorSize / kTensorChannels; ++i) {
float* data = (float*)inputData.mutableBytes;
for (int j = 0; j < kTensorChannels; ++j) {
data[i * kTensorChannels + j] = j;
}
}
TFLTensor* inputTensor = [interpreter inputTensorAtIndex:0 error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertTrue([inputTensor copyData:inputData error:&error]);
XCTAssertNil(error);
// Invokes the interpreter.
XCTAssertTrue([interpreter invokeWithError:&error]);
XCTAssertNil(error);
// Gets the output tensor data.
TFLTensor* outputTensor = [interpreter outputTensorAtIndex:0 error:&error];
NSData* outputData = [outputTensor dataWithError:&error];
XCTAssertNotNil(outputData);
XCTAssertNil(error);
float output[kTensorSize];
[outputData getBytes:output length:(sizeof(float) * kTensorSize)];
for (int i = 0; i < kTensorSize / kTensorChannels; ++i) {
for (int j = 0; j < kTensorChannels; ++j) {
XCTAssertEqualWithAccuracy(j * 3, output[i * kTensorChannels + j], kTestAccuracy);
}
}
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,58 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "tensorflow/lite/objc/apis/TFLInterpreterOptions.h"
#import <XCTest/XCTest.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Unit tests for TFLInterpreterOptions.
*/
@interface TFLInterpreterOptionsTests : XCTestCase
@end
@implementation TFLInterpreterOptionsTests
#pragma mark - Tests
- (void)testInit {
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
XCTAssertNotNil(options);
XCTAssertEqual(options.numberOfThreads, 0);
XCTAssertFalse(options.useXNNPACK);
}
- (void)testSetNumberOfThread {
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
options.numberOfThreads = 2;
XCTAssertEqual(options.numberOfThreads, 2);
options.numberOfThreads = 0;
XCTAssertEqual(options.numberOfThreads, 0);
options.numberOfThreads = 3;
XCTAssertEqual(options.numberOfThreads, 3);
}
- (void)testUseXNNPACK {
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
options.useXNNPACK = YES;
XCTAssertTrue(options.useXNNPACK);
options.useXNNPACK = NO;
XCTAssertFalse(options.useXNNPACK);
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,376 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h"
#import <XCTest/XCTest.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Regular expression for TensorFlow Lite runtime version string, e.g. "1.14.0", "0.1.2-alpha.1",
* "0.3.4-beta2", "1.14.0-rc.3", "2.20.0-dev0+selfbuilt".
*/
static NSString *const kTFLVersionRegex = @"^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.-]+)?(\\+\\w+)?$";
/** Float model resource name. */
static NSString *const kAddFloatModelResourceName = @"add";
/** Quantized model resource name. */
static NSString *const kAddQuantizedModelResourceName = @"add_quantized";
/** Model resource type. */
static NSString *const kAddModelResourceType = @"bin";
/** Size of the first (and only) dimension of the input and output tensor in the Add model. */
enum EnumType : NSUInteger {kAddModelTensorFirstDimensionSize = 2U};
/** Quantization scale of the quantized model. */
static const float kAddQuantizedModelScale = 0.003922F;
/** Quantization zero point of the quantized model. */
static const int32_t kAddQuantizedModelZeroPoint = 0;
/** Invalid input tensor index. */
static const NSUInteger kInvalidInputTensorIndex = 1U;
/** Invalid output tensor index. */
static const NSUInteger kInvalidOutputTensorIndex = 1U;
/** Accuracy used in comparing floating numbers. */
static const float kTestAccuracy = 1E-5F;
/**
* Unit tests for TFLInterpreter.
*/
@interface TFLInterpreterTests : XCTestCase
/** Absolute path of the Add float model resource. */
@property(nonatomic, nullable) NSString *floatModelPath;
/** Default interpreter using the Add model. */
@property(nonatomic, nullable) TFLInterpreter *interpreter;
@end
@implementation TFLInterpreterTests
#pragma mark - XCTestCase
- (void)setUp {
[super setUp];
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
self.floatModelPath = [bundle pathForResource:kAddFloatModelResourceName
ofType:kAddModelResourceType];
NSError *error;
self.interpreter = [[TFLInterpreter alloc] initWithModelPath:self.floatModelPath error:&error];
XCTAssertNil(error);
XCTAssertNotNil(self.interpreter);
XCTAssertTrue([self.interpreter allocateTensorsWithError:nil]);
}
- (void)tearDown {
self.floatModelPath = nil;
self.interpreter = nil;
[super tearDown];
}
#pragma mark - Tests
- (void)testTFLVersion {
NSLog(@"TFLVersion: %@", TFLVersion);
NSRange range = [TFLVersion rangeOfString:kTFLVersionRegex options:NSRegularExpressionSearch];
XCTAssertNotEqual(range.location, NSNotFound);
}
- (void)testSuccessfulFullRunAddFloatModel {
// Shape for both input and output tensor.
NSArray<NSNumber *> *shape = @[ @(kAddModelTensorFirstDimensionSize) ];
// Creates the interpreter options.
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
XCTAssertNotNil(options);
options.numberOfThreads = 2;
// Creates the interpreter.
NSError *error;
TFLInterpreter *customInterpreter = [[TFLInterpreter alloc] initWithModelPath:self.floatModelPath
options:options
delegates:@[]
error:&error];
XCTAssertNil(error);
XCTAssertNotNil(customInterpreter);
// Allocates memory for tensors.
XCTAssertTrue([customInterpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Verifies input and output tensor counts.
XCTAssertEqual(customInterpreter.inputTensorCount, 1);
XCTAssertEqual(customInterpreter.outputTensorCount, 1);
// Resizes the intput tensor.
XCTAssertTrue([customInterpreter resizeInputTensorAtIndex:0 toShape:shape error:&error]);
XCTAssertNil(error);
// Re-allocates memory for tensors.
XCTAssertTrue([customInterpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Verifies the input tensor.
TFLTensor *inputTensor = [customInterpreter inputTensorAtIndex:0 error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertNil(error);
XCTAssertTrue([inputTensor.name isEqualToString:@"input"]);
XCTAssertEqual(inputTensor.dataType, TFLTensorDataTypeFloat32);
NSArray<NSNumber *> *inputTensorShape = [inputTensor shapeWithError:&error];
XCTAssertNil(error);
XCTAssertTrue([shape isEqualToArray:inputTensorShape]);
// Copies the input data.
NSMutableData *inputData = [NSMutableData dataWithCapacity:0];
float one = 1.f;
float three = 3.f;
[inputData appendBytes:&one length:sizeof(float)];
[inputData appendBytes:&three length:sizeof(float)];
XCTAssertTrue([inputTensor copyData:inputData error:&error]);
XCTAssertNil(error);
// Invokes the interpreter.
XCTAssertTrue([customInterpreter invokeWithError:&error]);
XCTAssertNil(error);
// Verifies the output tensor.
TFLTensor *outputTensor = [customInterpreter outputTensorAtIndex:0 error:&error];
XCTAssertNotNil(outputTensor);
XCTAssertNil(error);
XCTAssertTrue([outputTensor.name isEqualToString:@"output"]);
XCTAssertEqual(outputTensor.dataType, TFLTensorDataTypeFloat32);
NSArray<NSNumber *> *outputTensorShape = [outputTensor shapeWithError:&error];
XCTAssertNil(error);
XCTAssertTrue([shape isEqualToArray:outputTensorShape]);
// Tries to query an invalid output tensor index.
TFLTensor *invalidOutputTensor = [customInterpreter outputTensorAtIndex:kInvalidOutputTensorIndex
error:&error];
XCTAssertNil(invalidOutputTensor);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidTensorIndex);
// Gets the output tensor data.
error = nil;
NSData *outputData = [outputTensor dataWithError:&error];
XCTAssertNotNil(outputData);
XCTAssertNil(error);
float output[kAddModelTensorFirstDimensionSize];
[outputData getBytes:output length:(sizeof(float) * kAddModelTensorFirstDimensionSize)];
XCTAssertEqualWithAccuracy(output[0], 3.f, kTestAccuracy);
XCTAssertEqualWithAccuracy(output[1], 9.f, kTestAccuracy);
}
- (void)testSuccessfulFullRunQuantizedModel {
// Shape for both input and output tensor.
NSArray<NSNumber *> *shape = @[ @(kAddModelTensorFirstDimensionSize) ];
// Creates the interpreter options.
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
XCTAssertNotNil(options);
options.numberOfThreads = 2;
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *quantizedModelPath = [bundle pathForResource:kAddQuantizedModelResourceName
ofType:kAddModelResourceType];
// Creates the interpreter.
NSError *error;
TFLInterpreter *customInterpreter = [[TFLInterpreter alloc] initWithModelPath:quantizedModelPath
options:options
delegates:@[]
error:&error];
XCTAssertNil(error);
XCTAssertNotNil(customInterpreter);
// Allocates memory for tensors.
XCTAssertTrue([customInterpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Verifies input and output tensor counts.
XCTAssertEqual(customInterpreter.inputTensorCount, 1);
XCTAssertEqual(customInterpreter.outputTensorCount, 1);
// Resizes the intput tensor.
XCTAssertTrue([customInterpreter resizeInputTensorAtIndex:0 toShape:shape error:&error]);
XCTAssertNil(error);
// Re-allocates memory for tensors.
XCTAssertTrue([customInterpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Verifies the input tensor.
TFLTensor *inputTensor = [customInterpreter inputTensorAtIndex:0 error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertNil(error);
XCTAssertTrue([inputTensor.name isEqualToString:@"input"]);
XCTAssertEqual(inputTensor.dataType, TFLTensorDataTypeUInt8);
XCTAssertEqualWithAccuracy(inputTensor.quantizationParameters.scale, kAddQuantizedModelScale,
kTestAccuracy);
XCTAssertEqual(inputTensor.quantizationParameters.zeroPoint, kAddQuantizedModelZeroPoint);
NSArray<NSNumber *> *inputTensorShape = [inputTensor shapeWithError:&error];
XCTAssertNil(error);
XCTAssertTrue([shape isEqualToArray:inputTensorShape]);
// Copies the input data.
NSMutableData *inputData = [NSMutableData dataWithCapacity:0];
uint8_t one = 1;
uint8_t three = 3;
[inputData appendBytes:&one length:sizeof(uint8_t)];
[inputData appendBytes:&three length:sizeof(uint8_t)];
XCTAssertTrue([inputTensor copyData:inputData error:&error]);
XCTAssertNil(error);
// Invokes the interpreter.
XCTAssertTrue([customInterpreter invokeWithError:&error]);
XCTAssertNil(error);
// Verifies the output tensor.
TFLTensor *outputTensor = [customInterpreter outputTensorAtIndex:0 error:&error];
XCTAssertNotNil(outputTensor);
XCTAssertNil(error);
XCTAssertTrue([outputTensor.name isEqualToString:@"output"]);
XCTAssertEqual(outputTensor.dataType, TFLTensorDataTypeUInt8);
XCTAssertEqualWithAccuracy(outputTensor.quantizationParameters.scale, kAddQuantizedModelScale,
kTestAccuracy);
XCTAssertEqual(outputTensor.quantizationParameters.zeroPoint, kAddQuantizedModelZeroPoint);
NSArray<NSNumber *> *outputTensorShape = [outputTensor shapeWithError:&error];
XCTAssertNil(error);
XCTAssertTrue([shape isEqualToArray:outputTensorShape]);
// Tries to query an invalid output tensor index.
TFLTensor *invalidOutputTensor = [customInterpreter outputTensorAtIndex:kInvalidOutputTensorIndex
error:&error];
XCTAssertNil(invalidOutputTensor);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidTensorIndex);
// Gets the output tensor data.
error = nil;
NSData *outputData = [outputTensor dataWithError:&error];
XCTAssertNotNil(outputData);
XCTAssertNil(error);
uint8_t output[kAddModelTensorFirstDimensionSize];
[outputData getBytes:output length:(sizeof(uint8_t) * kAddModelTensorFirstDimensionSize)];
XCTAssertEqual(output[0], 3);
XCTAssertEqual(output[1], 9);
}
- (void)testInitWithModelPath_invalidPath {
// Creates the interpreter.
NSError *error;
TFLInterpreter *brokenInterpreter = [[TFLInterpreter alloc] initWithModelPath:@"InvalidPath"
error:&error];
XCTAssertNil(brokenInterpreter);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeFailedToLoadModel);
}
- (void)testInvoke_beforeAllocation {
NSError *error;
TFLInterpreter *interpreterWithoutAllocation =
[[TFLInterpreter alloc] initWithModelPath:self.floatModelPath error:&error];
XCTAssertNotNil(interpreterWithoutAllocation);
XCTAssertNil(error);
XCTAssertFalse([interpreterWithoutAllocation invokeWithError:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeFailedToInvoke);
}
- (void)testInputTensorAtIndex_invalidIndex {
NSError *error;
TFLTensor *inputTensor = [self.interpreter inputTensorAtIndex:kInvalidInputTensorIndex
error:&error];
XCTAssertNil(inputTensor);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidTensorIndex);
}
- (void)testResizeInputTensorAtIndex_invalidIndex {
NSArray<NSNumber *> *shape = @[ @(kAddModelTensorFirstDimensionSize) ];
NSError *error;
XCTAssertFalse([self.interpreter resizeInputTensorAtIndex:kInvalidInputTensorIndex
toShape:shape
error:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidTensorIndex);
}
- (void)testResizeInputTensorAtIndex_emptyShape {
NSMutableArray<NSNumber *> *emptyShape = [NSMutableArray arrayWithCapacity:0];
NSError *error;
XCTAssertFalse([self.interpreter resizeInputTensorAtIndex:0 toShape:emptyShape error:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidShape);
}
- (void)testResizeInputTensorAtIndex_zeroDimensionSize {
NSArray<NSNumber *> *shape = @[ @0 ];
NSError *error;
XCTAssertFalse([self.interpreter resizeInputTensorAtIndex:0 toShape:shape error:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidShape);
}
- (void)testCopyDataToInputTensorAtIndex_invalidInputDataByteSize {
NSMutableData *inputData = [NSMutableData dataWithCapacity:0];
float one = 1.f;
float three = 3.f;
[inputData appendBytes:&one length:sizeof(float)];
[inputData appendBytes:&three length:(sizeof(float) - 1)];
NSError *error;
TFLTensor *inputTensor = [self.interpreter inputTensorAtIndex:0 error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertNil(error);
XCTAssertFalse([inputTensor copyData:inputData error:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeInvalidInputByteSize);
}
- (void)testCopyDataToOutputTensorAtIndex_notAllowed {
NSMutableData *data = [NSMutableData dataWithCapacity:0];
float one = 1.f;
float three = 3.f;
[data appendBytes:&one length:sizeof(float)];
[data appendBytes:&three length:(sizeof(float) - 1)];
NSError *error;
TFLTensor *outputTensor = [self.interpreter outputTensorAtIndex:0 error:&error];
XCTAssertNotNil(outputTensor);
XCTAssertNil(error);
XCTAssertFalse([outputTensor copyData:data error:&error]);
XCTAssertEqual(error.code, TFLInterpreterErrorCodeCopyDataToOutputTensorNotAllowed);
}
- (void)testNilCDelegate {
// Creates the interpreter options.
TFLInterpreterOptions *options = [[TFLInterpreterOptions alloc] init];
// Creates the interpreter.
NSError *error;
TFLDelegate *delegate = [[TFLDelegate alloc] init]; // Base delegate's cDelegate is nil.
TFLInterpreter *customInterpreter = [[TFLInterpreter alloc] initWithModelPath:self.floatModelPath
options:options
delegates:@[ delegate ]
error:&error];
XCTAssertNil(error);
XCTAssertNotNil(customInterpreter);
// Allocates memory for tensors.
XCTAssertTrue([customInterpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,124 @@
// Copyright 2020 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifdef COCOAPODS
@import TFLTensorFlowLite;
#else
#import "tensorflow/lite/objc/apis/TFLMetalDelegate.h"
#import "tensorflow/lite/objc/apis/TFLTensorFlowLite.h"
#endif
#import <Metal/MTLDevice.h>
#import <Metal/Metal.h>
#import <XCTest/XCTest.h>
NS_ASSUME_NONNULL_BEGIN
/**
* Float model resource name.
* The model has four inputs (a, b, c, d) and two outputs (x, y)
* x = a + (b + c)
* y = (b + c) + d
*/
static NSString* const kAddFloatModelResourceName = @"multi_add";
/** Model resource type. */
static NSString* const kAddModelResourceType = @"bin";
/**
* @var kTensorSize
* Size of input and output tensors
* @var kTensorChannels
* Size of channel dimension of input and output tensors
*/
enum EnumType : int {kTensorSize = 8 * 8 * 3, kTensorChannels = 3};
/** Number of input tensors */
static const int kNumInputs = 4;
/** Number of output tensors */
static const int kNumOutputs = 2;
/** Accuracy used in comparing floating numbers. */
static const float kTestAccuracy = 1E-5F;
@interface TFLMetalDelegateTests : XCTestCase
@end
@implementation TFLMetalDelegateTests
- (void)testMetalDelegate {
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* floatModelPath = [bundle pathForResource:kAddFloatModelResourceName
ofType:kAddModelResourceType];
TFLInterpreterOptions* options = [[TFLInterpreterOptions alloc] init];
TFLMetalDelegate* metalDelegate = [[TFLMetalDelegate alloc] init];
XCTAssertNotNil(metalDelegate);
id<MTLDevice> mtlDevice = MTLCreateSystemDefaultDevice();
if (mtlDevice == nil) return; // Stop testing if there's no GPU support
NSError* error;
TFLInterpreter* interpreter = [[TFLInterpreter alloc] initWithModelPath:floatModelPath
options:options
delegates:@[ metalDelegate ]
error:&error];
XCTAssertNil(error);
XCTAssertNotNil(interpreter);
XCTAssertTrue([interpreter allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Copies the input data. For each input, input[i, j, k] == k
NSMutableData* inputData = [NSMutableData dataWithLength:sizeof(float) * kTensorSize];
for (int i = 0; i < kTensorSize / kTensorChannels; ++i) {
float* data = (float*)inputData.mutableBytes;
for (int j = 0; j < kTensorChannels; ++j) {
data[i * kTensorChannels + j] = j;
}
}
for (int input_idx = 0; input_idx < kNumInputs; ++input_idx) {
TFLTensor* inputTensor = [interpreter inputTensorAtIndex:input_idx error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertTrue([inputTensor copyData:inputData error:&error]);
XCTAssertNil(error);
}
// Invokes the interpreter.
XCTAssertTrue([interpreter invokeWithError:&error]);
XCTAssertNil(error);
// Gets the output tensor data. For each output, output[i, j, k] == k * 3
for (int output_idx = 0; output_idx < kNumOutputs; ++output_idx) {
TFLTensor* outputTensor = [interpreter outputTensorAtIndex:output_idx error:&error];
NSData* outputData = [outputTensor dataWithError:&error];
XCTAssertNotNil(outputData);
XCTAssertNil(error);
float output[kTensorSize];
[outputData getBytes:output length:(sizeof(float) * kTensorSize)];
for (int i = 0; i < kTensorSize / kTensorChannels; ++i) {
for (int j = 0; j < kTensorChannels; ++j) {
XCTAssertEqualWithAccuracy(j * 3, output[i * kTensorChannels + j], kTestAccuracy);
}
}
}
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,48 @@
// Copyright 2018 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "tensorflow/lite/objc/apis/TFLQuantizationParameters.h"
#import <XCTest/XCTest.h>
#import "tensorflow/lite/objc/sources/TFLQuantizationParameters+Internal.h"
NS_ASSUME_NONNULL_BEGIN
/** Test scale of quantization parameters. */
static const float kTestScale = 2.0;
/** Test zero point of quantization parameters. */
static const int32_t kTestZeroPoint = 128;
/**
* Unit tests for TFLQuantizationParameters.
*/
@interface TFLQuantizationParametersTests : XCTestCase
@end
@implementation TFLQuantizationParametersTests
#pragma mark - Tests
- (void)testInitWithScaleAndZeroPoint {
TFLQuantizationParameters *params =
[[TFLQuantizationParameters alloc] initWithScale:kTestScale zeroPoint:kTestZeroPoint];
XCTAssertEqual(params.scale, kTestScale);
XCTAssertEqual(params.zeroPoint, kTestZeroPoint);
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,224 @@
// Copyright 2022 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#import "tensorflow/lite/objc/apis/TFLInterpreter.h"
#import "tensorflow/lite/objc/apis/TFLQuantizationParameters.h"
#import "tensorflow/lite/objc/apis/TFLSignatureRunner.h"
#import "tensorflow/lite/objc/apis/TFLTensor.h"
#import <XCTest/XCTest.h>
/** Multiple signatures model resource name. */
static NSString *const kMultiSignaturesModelResourceName = @"multi_signatures";
/** Model resource type. */
static NSString *const kModelResourceType = @"bin";
static NSString *const kAddSignatureKey = @"add";
static NSString *const kSubSignatureKey = @"sub";
static NSString *const kDummySignatureKey = @"dummy";
@interface TFLSignatureRunnerTest : XCTestCase
/** Absolute path of the multi-signature model resource. */
@property(nonatomic, nullable) NSString *multiSignaturesModelPath;
@end
@implementation TFLSignatureRunnerTest
- (void)setUp {
[super setUp];
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
self.multiSignaturesModelPath = [bundle pathForResource:kMultiSignaturesModelResourceName
ofType:kModelResourceType];
}
- (void)tearDown {
self.multiSignaturesModelPath = nil;
[super tearDown];
}
- (void)testSignatureKeys {
NSError *error;
TFLInterpreter *interpreter =
[[TFLInterpreter alloc] initWithModelPath:self.multiSignaturesModelPath error:&error];
XCTAssertNil(error);
XCTAssertNotNil(interpreter);
NSArray<NSString *> *signatureKeys = interpreter.signatureKeys;
NSArray<NSString *> *expectedKeys = @[ kAddSignatureKey, kSubSignatureKey ];
XCTAssertTrue([signatureKeys isEqualToArray:expectedKeys]);
// Validate signature runner for "add" signature.
XCTAssertNotNil([interpreter signatureRunnerWithKey:kAddSignatureKey error:&error]);
XCTAssertNil(error);
// Test fail to get signature runner for dummy signature.
XCTAssertNil([interpreter signatureRunnerWithKey:kDummySignatureKey error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeFailedToCreateSignatureRunner);
}
- (void)testResizeInputTensor {
NSError *error;
TFLInterpreter *interpreter =
[[TFLInterpreter alloc] initWithModelPath:self.multiSignaturesModelPath error:&error];
TFLSignatureRunner *addRunner = [interpreter signatureRunnerWithKey:kAddSignatureKey
error:&error];
XCTAssertNil(error);
NSArray<NSString *> *expectedInputs = @[ @"x" ];
XCTAssertTrue([addRunner.inputs isEqualToArray:expectedInputs]);
// Validate signature "add" input tensor "x" before resizing.
TFLTensor *inputTensor = [addRunner inputTensorWithName:@"x" error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertEqual(inputTensor.dataType, TFLTensorDataTypeFloat32);
XCTAssertTrue([[inputTensor shapeWithError:&error] isEqualToArray:@[ @(1) ]]);
XCTAssertNil(error);
XCTAssertEqual([inputTensor dataWithError:&error].length, 4U);
XCTAssertNil(error);
XCTAssertEqual(inputTensor.quantizationParameters.scale, 0.);
XCTAssertEqual(inputTensor.quantizationParameters.zeroPoint, 0U);
// Test fail to copy data before resizing the tensor
float inputs[2] = {2.f, 4.f};
NSData *inputData = [NSData dataWithBytes:&inputs length:(2 * sizeof(float))];
XCTAssertFalse([inputTensor copyData:inputData error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeInvalidInputByteSize);
error = nil;
// Resize signature "add" input tensor "x"
NSArray<NSNumber *> *newShape = @[ @(2) ];
XCTAssertTrue([addRunner resizeInputTensorWithName:@"x" toShape:newShape error:&error]);
XCTAssertNil(error);
XCTAssertTrue([addRunner allocateTensorsWithError:&error]);
XCTAssertNil(error);
// Validate signature "add" input tensor "x" after resizing.
inputTensor = [addRunner inputTensorWithName:@"x" error:&error];
XCTAssertNotNil(inputTensor);
XCTAssertEqual(inputTensor.dataType, TFLTensorDataTypeFloat32);
XCTAssertTrue([[inputTensor shapeWithError:&error] isEqualToArray:newShape]);
XCTAssertNil(error);
XCTAssertEqual([inputTensor dataWithError:&error].length, 8U);
XCTAssertNil(error);
XCTAssertEqual(inputTensor.quantizationParameters.scale, 0.);
XCTAssertEqual(inputTensor.quantizationParameters.zeroPoint, 0U);
// Validate input tensor "x" after copying data
XCTAssertTrue([inputTensor copyData:inputData error:&error]);
XCTAssertNil(error);
NSData *retrievedInputData = [inputTensor dataWithError:&error];
XCTAssertNil(error);
float retrievedInputs[2];
[retrievedInputData getBytes:&retrievedInputs length:retrievedInputData.length];
XCTAssertEqual(retrievedInputs[0], inputs[0]);
XCTAssertEqual(retrievedInputs[1], inputs[1]);
}
- (void)testResizeInputTensor_invalidTensor {
NSError *error;
TFLInterpreter *interpreter =
[[TFLInterpreter alloc] initWithModelPath:self.multiSignaturesModelPath error:&error];
TFLSignatureRunner *addRunner = [interpreter signatureRunnerWithKey:kAddSignatureKey
error:&error];
XCTAssertNil(error);
// Test fail to get input tensor for a dummy input name.
XCTAssertNil([addRunner inputTensorWithName:@"dummy" error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeFailedToGetTensor);
// Test fail to resize a dummy input tensor
error = nil;
XCTAssertFalse([addRunner resizeInputTensorWithName:@"dummy" toShape:@[ @(2) ] error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeFailedToResizeInputTensor);
}
- (void)testInvokeWithInputs {
NSError *error;
TFLInterpreter *interpreter =
[[TFLInterpreter alloc] initWithModelPath:self.multiSignaturesModelPath error:&error];
TFLSignatureRunner *addRunner = [interpreter signatureRunnerWithKey:kAddSignatureKey
error:&error];
XCTAssertNil(error);
// Validate signature "add" output tensor "output_0" before inference
NSArray<NSString *> *expectedOutputs = @[ @"output_0" ];
XCTAssertTrue([addRunner.outputs isEqualToArray:expectedOutputs]);
TFLTensor *outputTensor = [addRunner outputTensorWithName:@"output_0" error:&error];
XCTAssertNotNil(outputTensor);
XCTAssertEqual(outputTensor.dataType, TFLTensorDataTypeFloat32);
XCTAssertTrue([[outputTensor shapeWithError:&error] isEqualToArray:@[ @(1) ]]);
XCTAssertNil(error);
XCTAssertEqual([outputTensor dataWithError:&error].length, 4U);
XCTAssertNil(error);
XCTAssertEqual(outputTensor.quantizationParameters.scale, 0.);
XCTAssertEqual(outputTensor.quantizationParameters.zeroPoint, 0U);
// Resize signature "add" input tensor "x"
XCTAssertTrue([addRunner resizeInputTensorWithName:@"x" toShape:@[ @(2) ] error:&error]);
XCTAssertNil(error);
// Invoke signature "add" with inputs.
float inputs[2] = {2.f, 4.f};
NSData *inputData = [NSData dataWithBytes:&inputs length:(2 * sizeof(float))];
XCTAssertTrue([addRunner invokeWithInputs:@{@"x" : inputData} Error:&error]);
XCTAssertNil(error);
// Validate signature "add" output tensor "output_0" after inference
outputTensor = [addRunner outputTensorWithName:@"output_0" error:&error];
XCTAssertNotNil(outputTensor);
XCTAssertEqual(outputTensor.dataType, TFLTensorDataTypeFloat32);
XCTAssertTrue([[outputTensor shapeWithError:&error] isEqualToArray:@[ @(2) ]]);
XCTAssertNil(error);
XCTAssertEqual(outputTensor.quantizationParameters.scale, 0.);
XCTAssertEqual(outputTensor.quantizationParameters.zeroPoint, 0U);
NSData *outputData = [outputTensor dataWithError:&error];
XCTAssertNil(error);
XCTAssertEqual(outputData.length, 8U);
float outputs[2];
[outputData getBytes:&outputs length:outputData.length];
XCTAssertEqual(outputs[0], inputs[0] + 2.f);
XCTAssertEqual(outputs[1], inputs[1] + 2.f);
}
- (void)testInvokeWithInputs_invalidInputs {
NSError *error;
TFLInterpreter *interpreter =
[[TFLInterpreter alloc] initWithModelPath:self.multiSignaturesModelPath error:&error];
TFLSignatureRunner *addRunner = [interpreter signatureRunnerWithKey:kAddSignatureKey
error:&error];
XCTAssertNil(error);
// Invoke signature "add" with invalid input data.
float inputs[2] = {2.f, 4.f};
NSData *inputData = [NSData dataWithBytes:&inputs length:(2 * sizeof(float))];
XCTAssertFalse([addRunner invokeWithInputs:@{@"x" : inputData} Error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeInvalidInputByteSize);
// Invoke signature "add" with invalid input name.
error = nil;
float input = 2.f;
inputData = [NSData dataWithBytes:&input length:(1 * sizeof(float))];
XCTAssertFalse([addRunner invokeWithInputs:@{@"dummy" : inputData} Error:&error]);
XCTAssertNotNil(error);
XCTAssertEqual(error.code, TFLSignatureRunnerErrorCodeFailedToGetTensor);
}
@end