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,35 @@
// 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 <Foundation/Foundation.h>
#import "tensorflow/lite/objc/apis/TFLTensor.h"
NS_ASSUME_NONNULL_BEGIN
typedef struct TfLiteTensor TfLiteTensor;
@class TFLQuantizationParameters;
/** Gets the tensor data type from a c tensor. */
FOUNDATION_EXTERN TFLTensorDataType TFLTensorDataTypeFromCTensor(const TfLiteTensor *cTensor);
/** Gets the tensor name from a c tensor. */
FOUNDATION_EXTERN NSString *__nullable TFLTensorNameFromCTensor(const TfLiteTensor *cTensor);
/** Gets the quantization parameters from a c tensor. */
FOUNDATION_EXTERN TFLQuantizationParameters *__nullable
TFLQuantizationParamsFromCTensor(const TfLiteTensor *cTensor);
NS_ASSUME_NONNULL_END
@@ -0,0 +1,89 @@
// 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 "TFLCommonUtil.h"
#import "TFLQuantizationParameters+Internal.h"
#import "tensorflow/lite/objc/apis/TFLTensor.h"
#ifdef COCOAPODS
#import <TensorFlowLiteC/TensorFlowLiteC.h>
#else
#include "tensorflow/lite/core/c/c_api.h"
#endif // COCOAPODS
NS_ASSUME_NONNULL_BEGIN
TFLTensorDataType TFLTensorDataTypeFromCTensor(const TfLiteTensor *cTensor) {
TfLiteType cTensorType = TfLiteTensorType(cTensor);
switch (cTensorType) {
case kTfLiteFloat32:
return TFLTensorDataTypeFloat32;
case kTfLiteFloat16:
return TFLTensorDataTypeFloat16;
case kTfLiteBFloat16:
return TFLTensorDataTypeBFloat16;
case kTfLiteFloat64:
return TFLTensorDataTypeFloat64;
case kTfLiteInt32:
return TFLTensorDataTypeInt32;
case kTfLiteUInt8:
return TFLTensorDataTypeUInt8;
case kTfLiteInt8:
return TFLTensorDataTypeInt8;
case kTfLiteInt64:
return TFLTensorDataTypeInt64;
case kTfLiteBool:
return TFLTensorDataTypeBool;
case kTfLiteInt16:
return TFLTensorDataTypeInt16;
case kTfLiteNoType:
case kTfLiteString:
case kTfLiteComplex64:
case kTfLiteComplex128:
case kTfLiteUInt16:
case kTfLiteUInt32:
case kTfLiteUInt64:
case kTfLiteUInt4:
case kTfLiteInt4:
case kTfLiteInt2:
case kTfLiteResource:
case kTfLiteVariant:
case kTfLiteFloat8E4M3FN:
case kTfLiteFloat8E5M2:
// Not all datatypes are supported in the TfLite Objc API.
return TFLTensorDataTypeNoType;
}
}
NSString *__nullable TFLTensorNameFromCTensor(const TfLiteTensor *cTensor) {
const char *cName = TfLiteTensorName(cTensor);
if (cName == nullptr) return nil;
return [NSString stringWithUTF8String:cName];
}
TFLQuantizationParameters *__nullable
TFLQuantizationParamsFromCTensor(const TfLiteTensor *cTensor) {
TfLiteQuantizationParams cParams = TfLiteTensorQuantizationParams(cTensor);
TFLQuantizationParameters *quantizationParams;
// TODO(b/119735362): Update this check once the TfLiteQuantizationParams struct has a mode.
if (cParams.scale != 0.0) {
quantizationParams = [[TFLQuantizationParameters alloc] initWithScale:cParams.scale
zeroPoint:cParams.zero_point];
}
return quantizationParams;
}
NS_ASSUME_NONNULL_END
@@ -0,0 +1,86 @@
// 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.
#import "tensorflow/lite/objc/apis/TFLCoreMLDelegate.h"
#ifdef COCOAPODS
@import TensorFlowLiteCCoreML;
#else
#include "tensorflow/lite/delegates/coreml/coreml_delegate.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@implementation TFLCoreMLDelegateOptions
- (instancetype)init {
self = [super init];
if (self != nil) {
_coreMLVersion = 0;
_maxDelegatedPartitions = 0;
_minNodesPerPartition = 2;
_enabledDevices = TFLCoreMLDelegateEnabledDevicesNeuralEngine;
}
return self;
}
@end
@implementation TFLCoreMLDelegate
@synthesize cDelegate = _cDelegate;
#pragma mark - NSObject
- (void)dealloc {
TfLiteCoreMlDelegateDelete((TfLiteDelegate*)self.cDelegate);
}
#pragma mark - Public
- (nullable instancetype)init {
TFLCoreMLDelegateOptions* options = [[TFLCoreMLDelegateOptions alloc] init];
return [self initWithOptions:options];
}
- (nullable instancetype)initWithOptions:(TFLCoreMLDelegateOptions*)options {
self = [super init];
if (self != nil) {
TfLiteCoreMlDelegateOptions cOptions;
cOptions.coreml_version = options.coreMLVersion;
cOptions.max_delegated_partitions = options.maxDelegatedPartitions;
cOptions.min_nodes_per_partition = options.minNodesPerPartition;
switch (options.enabledDevices) {
case TFLCoreMLDelegateEnabledDevicesNeuralEngine:
cOptions.enabled_devices = TfLiteCoreMlDelegateDevicesWithNeuralEngine;
break;
case TFLCoreMLDelegateEnabledDevicesAll:
cOptions.enabled_devices = TfLiteCoreMlDelegateAllDevices;
break;
}
_cDelegate = TfLiteCoreMlDelegateCreate(&cOptions);
if (_cDelegate == nil) {
return nil;
}
}
return self;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,22 @@
// 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.
#import "tensorflow/lite/objc/apis/TFLDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TFLDelegate
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,53 @@
// 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 <Foundation/Foundation.h>
#import "tensorflow/lite/objc/apis/TFLInterpreter.h"
NS_ASSUME_NONNULL_BEGIN
/** Helper utility for error reporting. */
@interface TFLErrorUtil : NSObject
/**
* Creates and saves an interpreter error with the given error code and description.
*
* @param code Error code.
* @param description Error description.
* @param error Pointer to where to save the created error. If `nil`, no error will be saved.
*/
+ (void)saveInterpreterErrorWithCode:(TFLInterpreterErrorCode)code
description:(NSString *)description
error:(NSError **)error;
/**
* Sets the error with the given domain, error code and description.
*
* @param domain The error domain.
* @param code The error code.
* @param description The error description.
* @param error A pointer to populate the error. If `nil`, no error will be populated.
*/
+ (void)setError:(NSError **)error
withDomain:(NSErrorDomain)domain
code:(NSInteger)code
description:(NSString *)description;
/** Unavailable. */
- (instancetype)init NS_UNAVAILABLE;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,45 @@
// 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 "TFLErrorUtil.h"
NS_ASSUME_NONNULL_BEGIN
/** Error domain of TensorFlow Lite interpreter related errors. */
static NSString *const TFLInterpreterErrorDomain = @"org.tensorflow.lite.interpreter";
@implementation TFLErrorUtil
#pragma mark - Public
+ (void)saveInterpreterErrorWithCode:(TFLInterpreterErrorCode)code
description:(NSString *)description
error:(NSError **)error {
[self setError:error withDomain:TFLInterpreterErrorDomain code:code description:description];
}
+ (void)setError:(NSError **)error
withDomain:(NSErrorDomain)domain
code:(NSInteger)code
description:(NSString *)description {
if (error) {
*error = [NSError errorWithDomain:domain
code:code
userInfo:@{NSLocalizedDescriptionKey : description}];
}
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,30 @@
// 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/TFLInterpreter.h"
#import "TFLTensorDataAccessor.h"
typedef struct TfLiteInterpreter TfLiteInterpreter;
NS_ASSUME_NONNULL_BEGIN
@interface TFLInterpreter (Internal) <TFLTensorDataAccessor>
/** TfLiteInterpreter backed by C API. */
@property(nonatomic, readonly) TfLiteInterpreter *interpreter;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,459 @@
// 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/TFLInterpreter.h"
#include <vector>
#import "TFLCommonUtil.h"
#import "TFLErrorUtil.h"
#import "TFLQuantizationParameters+Internal.h"
#import "TFLSignatureRunner+Internal.h"
#import "TFLTensor+Internal.h"
#import "tensorflow/lite/objc/apis/TFLDelegate.h"
#import "tensorflow/lite/objc/apis/TFLInterpreterOptions.h"
#import "tensorflow/lite/objc/apis/TFLTensor.h"
#ifdef COCOAPODS
#import <TensorFlowLiteC/TensorFlowLiteC.h>
#else
#include "tensorflow/lite/core/c/c_api.h"
#include "tensorflow/lite/core/c/c_api_experimental.h"
#include "tensorflow/lite/delegates/xnnpack/xnnpack_delegate.h"
#endif // COCOAPODS
NS_ASSUME_NONNULL_BEGIN
FOUNDATION_EXPORT NSString *const TFLVersion =
TfLiteVersion() == nullptr ? @"" : [NSString stringWithUTF8String:TfLiteVersion()];
/**
* Error reporter for TFLInterpreter.
*
* @param user_data User data. Not used.
* @param format Error message which may contain argument formatting specifiers.
* @param args Values of the arguments in the error message.
*/
static void TFLInterpreterErrorReporter(void *user_data, const char *format, va_list args) {
NSLog(@"%@", [[NSString alloc] initWithFormat:@(format) arguments:args]);
}
@interface TFLInterpreter ()
/** TfLiteInterpreter backed by C API. */
@property(nonatomic) TfLiteInterpreter *interpreter;
/** TfLiteDelegate backed by C API. */
@property(nonatomic, nullable) TfLiteDelegate *xnnPackDelegate;
@end
@implementation TFLInterpreter
@synthesize signatureKeys = _signatureKeys;
#pragma mark - NSObject
- (void)dealloc {
TfLiteInterpreterDelete(_interpreter);
TfLiteXNNPackDelegateDelete(_xnnPackDelegate);
}
#pragma mark - Public
- (nullable instancetype)initWithModelPath:(NSString *)modelPath error:(NSError **)error {
return [self initWithModelPath:modelPath
options:[[TFLInterpreterOptions alloc] init]
delegates:@[]
error:error];
}
- (nullable instancetype)initWithModelPath:(NSString *)modelPath
options:(TFLInterpreterOptions *)options
error:(NSError **)error {
return [self initWithModelPath:modelPath options:options delegates:@[] error:error];
}
- (nullable instancetype)initWithModelPath:(NSString *)modelPath
options:(TFLInterpreterOptions *)options
delegates:(NSArray<TFLDelegate *> *)delegates
error:(NSError **)error {
self = [super init];
if (self != nil) {
TfLiteModel *model = nullptr;
TfLiteInterpreterOptions *cOptions = nullptr;
@try {
const char *modelPathCString = modelPath.UTF8String;
NSString *pathErrorString =
[NSString stringWithFormat:@"Cannot load model from path (%@).", modelPath];
if (modelPathCString == nullptr) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToLoadModel
description:pathErrorString
error:error];
return nil;
}
model = TfLiteModelCreateFromFile(modelPathCString);
if (model == nullptr) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToLoadModel
description:pathErrorString
error:error];
return nil;
}
cOptions = TfLiteInterpreterOptionsCreate();
if (cOptions == nullptr) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToCreateInterpreter
description:@"Failed to create the interpreter."
error:error];
return nil;
}
if (options.numberOfThreads > 0) {
TfLiteInterpreterOptionsSetNumThreads(cOptions, (int32_t)options.numberOfThreads);
}
TfLiteInterpreterOptionsSetErrorReporter(cOptions, TFLInterpreterErrorReporter, nullptr);
if (options.useXNNPACK) {
TfLiteXNNPackDelegateOptions xnnPackOptions = TfLiteXNNPackDelegateOptionsDefault();
if (options.numberOfThreads > 0) {
xnnPackOptions.num_threads = (int32_t)options.numberOfThreads;
}
_xnnPackDelegate = TfLiteXNNPackDelegateCreate(&xnnPackOptions);
TfLiteInterpreterOptionsAddDelegate(cOptions, _xnnPackDelegate);
}
for (TFLDelegate *delegate in delegates) {
if (delegate.cDelegate != nullptr) {
TfLiteInterpreterOptionsAddDelegate(
cOptions, reinterpret_cast<TfLiteDelegate *>(delegate.cDelegate));
}
}
TfLiteInterpreter *interpreter = TfLiteInterpreterCreate(model, cOptions);
if (interpreter == nullptr) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToCreateInterpreter
description:@"Failed to create the interpreter."
error:error];
return nil;
}
_interpreter = interpreter;
_inputTensorCount = (NSUInteger)TfLiteInterpreterGetInputTensorCount(_interpreter);
_outputTensorCount = (NSUInteger)TfLiteInterpreterGetOutputTensorCount(_interpreter);
if (_inputTensorCount <= 0 || _outputTensorCount <= 0) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToCreateInterpreter
description:@"Failed to create the interpreter."
error:error];
return nil;
}
} @finally {
TfLiteInterpreterOptionsDelete(cOptions);
TfLiteModelDelete(model);
}
}
return self;
}
- (NSArray<NSString *> *)signatureKeys {
if (_signatureKeys) return _signatureKeys;
NSUInteger signatureCount = TfLiteInterpreterGetSignatureCount(self.interpreter);
NSMutableArray<NSString *> *mutableKeyArray =
[[NSMutableArray alloc] initWithCapacity:signatureCount];
for (NSUInteger i = 0; i < signatureCount; i++) {
const char *signatureNameCString =
TfLiteInterpreterGetSignatureKey(self.interpreter, (int32_t)i);
NSString *signatureName = @"";
if (signatureNameCString != nullptr) {
signatureName = [NSString stringWithUTF8String:signatureNameCString] ?: @"";
}
[mutableKeyArray addObject:signatureName];
}
_signatureKeys = [mutableKeyArray copy];
return _signatureKeys;
}
- (BOOL)invokeWithError:(NSError **)error {
if (TfLiteInterpreterInvoke(self.interpreter) != kTfLiteOk) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToInvoke
description:@"Failed to invoke the interpreter."
error:error];
return NO;
}
return YES;
}
- (nullable TFLTensor *)inputTensorAtIndex:(NSUInteger)index error:(NSError **)error {
if (![self isValidTensorIndex:index belowLimit:self.inputTensorCount error:error]) {
return nil;
}
return [self tensorOfType:TFLTensorTypeInput atIndex:index error:error];
}
- (nullable TFLTensor *)outputTensorAtIndex:(NSUInteger)index error:(NSError **)error {
if (![self isValidTensorIndex:index belowLimit:self.outputTensorCount error:error]) {
return nil;
}
return [self tensorOfType:TFLTensorTypeOutput atIndex:index error:error];
}
- (BOOL)resizeInputTensorAtIndex:(NSUInteger)index
toShape:(NSArray<NSNumber *> *)shape
error:(NSError **)error {
if (![self isValidTensorIndex:index belowLimit:self.inputTensorCount error:error]) {
return NO;
}
if (shape.count == 0) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidShape
description:@"Invalid shape. Must not be empty."
error:error];
return NO;
}
std::vector<int> cDimensions(shape.count);
for (int dimIndex = 0; dimIndex < shape.count; ++dimIndex) {
int dimension = shape[dimIndex].intValue;
if (dimension <= 0) {
NSString *errorDescription = @"Invalid shape. Dimensions must be positive integers.";
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidShape
description:errorDescription
error:error];
return NO;
}
cDimensions[dimIndex] = dimension;
}
if (TfLiteInterpreterResizeInputTensor(self.interpreter, (int32_t)index, cDimensions.data(),
(int32_t)shape.count) != kTfLiteOk) {
NSString *errorDescription = [NSString
stringWithFormat:@"Failed to resize input tensor at index (%lu).", (unsigned long)index];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToResizeInputTensor
description:errorDescription
error:error];
return NO;
}
return YES;
}
- (BOOL)allocateTensorsWithError:(NSError **)error {
if (TfLiteInterpreterAllocateTensors(self.interpreter) != kTfLiteOk) {
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToAllocateTensors
description:@"Failed to allocate memory for tensors."
error:error];
return NO;
}
return YES;
}
- (nullable TFLSignatureRunner *)signatureRunnerWithKey:(NSString *)key error:(NSError **)error {
if (![self.signatureKeys containsObject:key]) {
NSString *errorDescription = [NSString
stringWithFormat:@"Failed to create a signature runner. Signature with key (%@) not found.",
key];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToCreateSignatureRunner
description:errorDescription];
return nil;
}
return [[TFLSignatureRunner alloc] initWithInterpreter:self signatureKey:key error:error];
}
#pragma mark - TFLTensorDataAccessor
- (BOOL)copyData:(NSData *)data toInputTensor:(TFLTensor *)inputTensor error:(NSError **)error {
if (inputTensor.type == TFLTensorTypeOutput) {
[TFLErrorUtil
saveInterpreterErrorWithCode:TFLInterpreterErrorCodeCopyDataToOutputTensorNotAllowed
description:@"Cannot copy data into an output tensor."
error:error];
return NO;
}
const TfLiteTensor *cTensor = [self cTensorOfType:TFLTensorTypeInput
atIndex:inputTensor.index
error:error];
if (cTensor == nullptr) {
return NO;
}
NSUInteger byteSize = (NSUInteger)TfLiteTensorByteSize(cTensor);
if (data.length != byteSize) {
NSString *errorDescription = [NSString
stringWithFormat:@"Input tensor at index (%lu) expects data size (%lu), but got (%lu).",
(unsigned long)index, (unsigned long)byteSize, (unsigned long)data.length];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidInputByteSize
description:errorDescription
error:error];
return NO;
}
if (TfLiteTensorCopyFromBuffer((TfLiteTensor *)cTensor, data.bytes, data.length) != kTfLiteOk) {
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to copy data into input tensor at index (%lu).",
(unsigned long)index];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToCopyDataToInputTensor
description:errorDescription
error:error];
return NO;
}
return YES;
}
- (nullable NSData *)dataFromTensor:(TFLTensor *)tensor error:(NSError **)error {
const TfLiteTensor *cTensor = [self cTensorOfType:tensor.type atIndex:tensor.index error:error];
if (cTensor == nullptr) {
return nil;
}
void *bytes = TfLiteTensorData(cTensor);
NSUInteger byteSize = (NSUInteger)TfLiteTensorByteSize(cTensor);
if (bytes == nullptr || byteSize == 0) {
NSString *tensorType = [TFLTensor stringForTensorType:tensor.type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get data from %@ tensor at index (%lu).", tensorType,
(unsigned long)tensor.index];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToGetDataFromTensor
description:errorDescription
error:error];
return nil;
}
return [NSData dataWithBytes:bytes length:byteSize];
}
- (nullable NSArray<NSNumber *> *)shapeOfTensor:(TFLTensor *)tensor error:(NSError **)error {
const TfLiteTensor *cTensor = [self cTensorOfType:tensor.type atIndex:tensor.index error:error];
if (cTensor == nullptr) {
return nil;
}
NSString *tensorType = [TFLTensor stringForTensorType:tensor.type];
int32_t rank = TfLiteTensorNumDims(cTensor);
if (rank <= 0) {
NSString *errorDescription =
[NSString stringWithFormat:@"%@ tensor at index (%lu) has invalid rank (%d).", tensorType,
(unsigned long)tensor.index, rank];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidTensor
description:errorDescription
error:error];
return nil;
}
NSMutableArray<NSNumber *> *shape = [NSMutableArray arrayWithCapacity:rank];
for (int32_t dimIndex = 0; dimIndex < rank; dimIndex++) {
int32_t dimension = TfLiteTensorDim(cTensor, dimIndex);
if (dimension <= 0) {
NSString *errorDescription =
[NSString stringWithFormat:@"%@ tensor at index (%lu) has invalid %d-th dimension (%d).",
tensorType, (unsigned long)tensor.index, dimIndex, dimension];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidTensor
description:errorDescription
error:error];
return nil;
}
shape[dimIndex] = @((NSUInteger)dimension);
}
return shape;
}
#pragma mark - Private
- (const TfLiteTensor *)cTensorOfType:(TFLTensorType)type
atIndex:(NSUInteger)index
error:(NSError **)error {
const TfLiteTensor *tensor = nullptr;
switch (type) {
case TFLTensorTypeInput:
tensor = TfLiteInterpreterGetInputTensor(self.interpreter, (int32_t)index);
break;
case TFLTensorTypeOutput:
tensor = TfLiteInterpreterGetOutputTensor(self.interpreter, (int32_t)index);
break;
}
if (tensor == nullptr) {
NSString *tensorType = [TFLTensor stringForTensorType:type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get %@ tensor at index (%lu).", tensorType,
(unsigned long)index];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeFailedToGetTensor
description:errorDescription
error:error];
}
return tensor;
}
- (nullable TFLTensor *)tensorOfType:(TFLTensorType)type
atIndex:(NSUInteger)index
error:(NSError **)error {
const TfLiteTensor *tensor = [self cTensorOfType:type atIndex:index error:error];
if (tensor == nullptr) {
return nil;
}
NSString *name = TFLTensorNameFromCTensor(tensor);
if (!name) {
NSString *tensorType = [TFLTensor stringForTensorType:type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get name of %@ tensor at index (%lu).", tensorType,
(unsigned long)index];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidTensor
description:errorDescription
error:error];
return nil;
}
TFLTensorDataType dataType = TFLTensorDataTypeFromCTensor(tensor);
TFLQuantizationParameters *quantizationParams = TFLQuantizationParamsFromCTensor(tensor);
return [[TFLTensor alloc] initWithInterpreter:self
type:type
index:index
name:name
dataType:dataType
quantizationParameters:quantizationParams];
}
- (BOOL)isValidTensorIndex:(NSUInteger)index
belowLimit:(NSUInteger)totalTensorCount
error:(NSError **)error {
if (index >= totalTensorCount) {
NSString *errorDescription =
[NSString stringWithFormat:@"Invalid tensor index (%lu) exceeds max (%lu).",
(unsigned long)index, (totalTensorCount - 1)];
[TFLErrorUtil saveInterpreterErrorWithCode:TFLInterpreterErrorCodeInvalidTensorIndex
description:errorDescription
error:error];
return NO;
}
return YES;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,30 @@
// 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"
NS_ASSUME_NONNULL_BEGIN
@implementation TFLInterpreterOptions
#pragma mark - Public
- (instancetype)init {
self = [super init];
return self;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,87 @@
// 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.
#import "tensorflow/lite/objc/apis/TFLMetalDelegate.h"
#ifdef COCOAPODS
@import TensorFlowLiteCMetal;
#else
#include "tensorflow/lite/delegates/gpu/metal_delegate.h"
#endif
NS_ASSUME_NONNULL_BEGIN
@implementation TFLMetalDelegateOptions
#pragma mark - Public
- (instancetype)init {
self = [super init];
if (self != nil) {
_quantizationEnabled = true;
_waitType = TFLMetalDelegateThreadWaitTypePassive;
}
return self;
}
@end
@implementation TFLMetalDelegate
@synthesize cDelegate = _cDelegate;
#pragma mark - NSObject
- (void)dealloc {
TFLGpuDelegateDelete(self.cDelegate);
}
#pragma mark - Public
- (nullable instancetype)init {
TFLMetalDelegateOptions* options = [[TFLMetalDelegateOptions alloc] init];
return [self initWithOptions:options];
}
- (nullable instancetype)initWithOptions:(TFLMetalDelegateOptions*)options {
self = [super init];
if (self != nil) {
TFLGpuDelegateOptions cOptions;
cOptions.allow_precision_loss = options.precisionLossAllowed;
cOptions.enable_quantization = options.quantizationEnabled;
switch (options.waitType) {
case TFLMetalDelegateThreadWaitTypeDoNotWait:
cOptions.wait_type = TFLGpuDelegateWaitTypeDoNotWait;
break;
case TFLMetalDelegateThreadWaitTypePassive:
cOptions.wait_type = TFLGpuDelegateWaitTypePassive;
break;
case TFLMetalDelegateThreadWaitTypeActive:
cOptions.wait_type = TFLGpuDelegateWaitTypeActive;
break;
case TFLMetalDelegateThreadWaitTypeAggressive:
cOptions.wait_type = TFLGpuDelegateWaitTypeAggressive;
break;
}
_cDelegate = TFLGpuDelegateCreate(&cOptions);
if (_cDelegate == nil) {
return nil;
}
}
return self;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,33 @@
// 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"
NS_ASSUME_NONNULL_BEGIN
@interface TFLQuantizationParameters (Internal)
/**
* Initializes a `TFLQuantizationParameters` instance with the given scale and zero point.
*
* @param scale Scale of asymmetric quantization.
* @param zeroPoint Zero point of asymmetric quantization.
*
* @return A new instance of `TFLQuantizationParameters` with the given scale and zero point.
*/
- (instancetype)initWithScale:(float)scale zeroPoint:(int32_t)zeroPoint;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,36 @@
// 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 "TFLQuantizationParameters+Internal.h"
NS_ASSUME_NONNULL_BEGIN
@implementation TFLQuantizationParameters
#pragma mark - TFLTensor (Internal)
- (instancetype)initWithScale:(float)scale zeroPoint:(int32_t)zeroPoint {
self = [super init];
if (self != nil) {
_scale = scale;
_zeroPoint = zeroPoint;
}
return self;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,43 @@
// 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/TFLSignatureRunner.h"
#import "TFLTensorDataAccessor.h"
@class TFLInterpreter;
NS_ASSUME_NONNULL_BEGIN
@interface TFLSignatureRunner (Internal) <TFLTensorDataAccessor>
/**
* Initializes a new TensorFlow Lite signature runner instance with the given interpreter and
* signature key.
*
* @param interpreter The TensorFlow Lite model interpreter.
* @param signatureKey The signature key.
* @param error An optional error parameter populated when there is an error in initializing the
* signature runner.
*
* @return A new instance of `TFLSignatureRunner` with the given model and options. `nil` if there
* is an error in initializing the signature runner.
*/
- (nullable instancetype)initWithInterpreter:(TFLInterpreter *)interpreter
signatureKey:(NSString *)signatureKey
error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,392 @@
// 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 "TFLSignatureRunner+Internal.h"
#include <vector>
#import "TFLCommonUtil.h"
#import "TFLErrorUtil.h"
#import "TFLInterpreter+Internal.h"
#import "TFLQuantizationParameters+Internal.h"
#import "TFLTensor+Internal.h"
#ifdef COCOAPODS
#import <TensorFlowLiteC/TensorFlowLiteC.h>
#else
#include "tensorflow/lite/core/c/c_api_experimental.h"
#endif // COCOAPODS
NS_ASSUME_NONNULL_BEGIN
/** Domain for errors in the signature runner. */
NSErrorDomain const TFLSignatureRunnerErrorDomain = @"org.tensorflow.lite.SignatureRunner";
@interface TFLSignatureRunner ()
/**
* The backing interpreter. It's a strong reference to ensure that the interpreter is never released
* before this signature runner is released.
*
* @warning Never let the interpreter hold a strong reference to the signature runner to avoid
* retain cycles.
*/
@property(nonatomic, readonly) TFLInterpreter *interpreter;
/** TfLiteSignatureRunner backed by C API. */
@property(nonatomic, readonly) TfLiteSignatureRunner *signatureRunner;
@end
@implementation TFLSignatureRunner {
// Whether we need to allocate tensors memory.
BOOL _isTensorsAllocationNeeded;
}
@synthesize inputs = _inputs;
@synthesize outputs = _outputs;
@synthesize signatureKey = _signatureKey;
#pragma mark - Initializer
- (nullable instancetype)initWithInterpreter:(TFLInterpreter *)interpreter
signatureKey:(NSString *)signatureKey
error:(NSError **)error {
self = [super init];
if (self != nil) {
_signatureKey = [signatureKey copy];
const char *signatureKeyCString = _signatureKey.UTF8String;
TfLiteSignatureRunner *signatureRunner =
TfLiteInterpreterGetSignatureRunner(interpreter.interpreter, signatureKeyCString);
if (signatureRunner == nullptr) {
NSString *errorDescription =
[NSString stringWithFormat:
@"Failed to create a signature runner. Signature with key (%@) not found.",
signatureKey];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToCreateSignatureRunner
description:errorDescription];
return nil;
}
_signatureRunner = signatureRunner;
_interpreter = interpreter;
_isTensorsAllocationNeeded = YES;
[self allocateTensorsWithError:error];
}
return self;
}
- (void)dealloc {
TfLiteSignatureRunnerDelete(_signatureRunner);
}
#pragma mark - Public
- (NSArray<NSString *> *)inputs {
if (_inputs) return _inputs;
NSUInteger inputCount = TfLiteSignatureRunnerGetInputCount(self.signatureRunner);
NSMutableArray<NSString *> *mutableInputsArray =
[[NSMutableArray alloc] initWithCapacity:inputCount];
for (NSUInteger i = 0; i < inputCount; i++) {
const char *inputNameCString =
TfLiteSignatureRunnerGetInputName(self.signatureRunner, (int32_t)i);
NSString *inputName = @"";
if (inputNameCString != nullptr) {
inputName = [NSString stringWithUTF8String:inputNameCString] ?: @"";
};
[mutableInputsArray addObject:inputName];
}
_inputs = [mutableInputsArray copy];
return _inputs;
}
- (NSArray<NSString *> *)outputs {
if (_outputs) return _outputs;
NSUInteger outputCount = TfLiteSignatureRunnerGetOutputCount(self.signatureRunner);
NSMutableArray<NSString *> *mutableOutputsArray =
[[NSMutableArray alloc] initWithCapacity:outputCount];
for (NSUInteger i = 0; i < outputCount; i++) {
const char *outputNameCString =
TfLiteSignatureRunnerGetOutputName(self.signatureRunner, (int32_t)i);
NSString *outputName = @"";
if (outputNameCString != nullptr) {
outputName = [NSString stringWithUTF8String:outputNameCString] ?: @"";
}
[mutableOutputsArray addObject:outputName];
}
_outputs = [mutableOutputsArray copy];
return _outputs;
}
- (nullable TFLTensor *)inputTensorWithName:(NSString *)name error:(NSError **)error {
return [self tensorOfType:TFLTensorTypeInput nameInSignature:name error:error];
}
- (nullable TFLTensor *)outputTensorWithName:(NSString *)name error:(NSError **)error {
return [self tensorOfType:TFLTensorTypeOutput nameInSignature:name error:error];
}
- (BOOL)resizeInputTensorWithName:(NSString *)name
toShape:(NSArray<NSNumber *> *)shape
error:(NSError **)error {
if (shape.count == 0) {
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidShape
description:@"Invalid shape. Must not be empty."];
return NO;
}
std::vector<int> cDimensions(shape.count);
for (int dimIndex = 0; dimIndex < shape.count; ++dimIndex) {
int dimension = shape[dimIndex].intValue;
if (dimension <= 0) {
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidShape
description:@"Invalid shape. Dimensions must be positive integers."];
return NO;
}
cDimensions[dimIndex] = dimension;
}
if (TfLiteSignatureRunnerResizeInputTensor(self.signatureRunner, name.UTF8String,
cDimensions.data(),
(int32_t)shape.count) != kTfLiteOk) {
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to resize input tensor with input name (%@).", name];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToResizeInputTensor
description:errorDescription];
return NO;
}
// Need to reallocate tensor memory.
_isTensorsAllocationNeeded = YES;
return YES;
}
- (BOOL)allocateTensorsWithError:(NSError **)error {
if (!_isTensorsAllocationNeeded) return YES;
if (TfLiteSignatureRunnerAllocateTensors(self.signatureRunner) != kTfLiteOk) {
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToAllocateTensors
description:@"Failed to allocate memory for tensors."];
return NO;
}
_isTensorsAllocationNeeded = NO;
return YES;
}
- (BOOL)invokeWithInputs:(NSDictionary<NSString *, NSData *> *)inputs Error:(NSError **)error {
if (![self allocateTensorsWithError:error]) return NO;
// Fill in input data.
for (NSString *inputName in inputs.allKeys) {
TFLTensor *inputTensor = [self inputTensorWithName:inputName error:error];
if (!inputTensor) return NO;
if (![inputTensor copyData:inputs[inputName] error:error]) return NO;
}
if (TfLiteSignatureRunnerInvoke(self.signatureRunner) != kTfLiteOk) {
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToInvoke
description:@"Failed to invoke the signature runner."];
return NO;
}
return YES;
}
#pragma mark - TFLTensorDataAccessor
- (BOOL)copyData:(NSData *)data toInputTensor:(TFLTensor *)inputTensor error:(NSError **)error {
if (inputTensor.type == TFLTensorTypeOutput) {
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeCopyDataToOutputTensorNotAllowed
description:@"Cannot copy data into an output tensor."];
return NO;
}
const TfLiteTensor *cTensor = [self cTensorOfType:TFLTensorTypeInput
nameInSignature:inputTensor.nameInSignature
error:error];
if (cTensor == nullptr) {
return NO;
}
NSUInteger byteSize = (NSUInteger)TfLiteTensorByteSize(cTensor);
if (data.length != byteSize) {
NSString *errorDescription = [NSString
stringWithFormat:
@"Input tensor with input name (%@) expects data size (%lu), but got (%lu).",
inputTensor.nameInSignature, (unsigned long)byteSize, (unsigned long)data.length];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidInputByteSize
description:errorDescription];
return NO;
}
if (TfLiteTensorCopyFromBuffer((TfLiteTensor *)cTensor, data.bytes, data.length) != kTfLiteOk) {
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to copy data into input tensor with input name (%@).",
inputTensor.nameInSignature];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToCopyDataToInputTensor
description:errorDescription];
return NO;
}
return YES;
}
- (nullable NSData *)dataFromTensor:(TFLTensor *)tensor error:(NSError **)error {
const TfLiteTensor *cTensor = [self cTensorOfType:tensor.type
nameInSignature:tensor.nameInSignature
error:error];
if (cTensor == nullptr) {
return nil;
}
void *bytes = TfLiteTensorData(cTensor);
NSUInteger byteSize = (NSUInteger)TfLiteTensorByteSize(cTensor);
if (bytes == nullptr || byteSize == 0) {
NSString *tensorType = [TFLTensor stringForTensorType:tensor.type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get data from %@ tensor with %@ name (%@).",
tensorType, tensorType, tensor.nameInSignature];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToGetDataFromTensor
description:errorDescription];
return nil;
}
return [NSData dataWithBytes:bytes length:byteSize];
}
- (nullable NSArray<NSNumber *> *)shapeOfTensor:(TFLTensor *)tensor error:(NSError **)error {
const TfLiteTensor *cTensor = [self cTensorOfType:tensor.type
nameInSignature:tensor.nameInSignature
error:error];
if (cTensor == nullptr) {
return nil;
}
NSString *tensorType = [TFLTensor stringForTensorType:tensor.type];
int32_t rank = TfLiteTensorNumDims(cTensor);
if (rank <= 0) {
NSString *errorDescription =
[NSString stringWithFormat:@"%@ tensor with %@ name (%@) has invalid rank (%d).",
tensorType, tensorType, tensor.nameInSignature, rank];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidTensor
description:errorDescription];
return nil;
}
NSMutableArray<NSNumber *> *shape = [NSMutableArray arrayWithCapacity:rank];
for (int32_t dimIndex = 0; dimIndex < rank; dimIndex++) {
int32_t dimension = TfLiteTensorDim(cTensor, dimIndex);
if (dimension <= 0) {
NSString *errorDescription = [NSString
stringWithFormat:@"%@ tensor with %@ name (%@) has invalid %d-th dimension (%d).",
tensorType, tensorType, tensor.nameInSignature, dimIndex, dimension];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidTensor
description:errorDescription];
return nil;
}
shape[dimIndex] = @((NSUInteger)dimension);
}
return shape;
}
#pragma mark - Private
- (nullable TFLTensor *)tensorOfType:(TFLTensorType)type
nameInSignature:(NSString *)nameInSignature
error:(NSError **)error {
const TfLiteTensor *tensor = [self cTensorOfType:type
nameInSignature:nameInSignature
error:error];
if (tensor == nullptr) {
return nil;
}
NSString *tensorName = TFLTensorNameFromCTensor(tensor);
if (!tensorName) {
NSString *tensorType = [TFLTensor stringForTensorType:type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get name of %@ tensor with %@ name (%@).",
tensorType, tensorType, nameInSignature];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeInvalidTensor
description:errorDescription];
return nil;
}
TFLTensorDataType dataType = TFLTensorDataTypeFromCTensor(tensor);
TFLQuantizationParameters *quantizationParams = TFLQuantizationParamsFromCTensor(tensor);
return [[TFLTensor alloc] initWithSignatureRunner:self
type:type
nameInSignature:nameInSignature
name:tensorName
dataType:dataType
quantizationParameters:quantizationParams];
}
- (const TfLiteTensor *)cTensorOfType:(TFLTensorType)type
nameInSignature:(NSString *)nameInSignature
error:(NSError **)error {
const TfLiteTensor *tensor = nullptr;
const char *nameCString = nameInSignature.UTF8String;
switch (type) {
case TFLTensorTypeInput:
tensor = TfLiteSignatureRunnerGetInputTensor(self.signatureRunner, nameCString);
break;
case TFLTensorTypeOutput:
tensor = TfLiteSignatureRunnerGetOutputTensor(self.signatureRunner, nameCString);
break;
}
if (tensor == nullptr) {
NSString *tensorType = [TFLTensor stringForTensorType:type];
NSString *errorDescription =
[NSString stringWithFormat:@"Failed to get %@ tensor with %@ name (%@).", tensorType,
tensorType, nameInSignature];
[TFLErrorUtil setError:error
withDomain:TFLSignatureRunnerErrorDomain
code:TFLSignatureRunnerErrorCodeFailedToGetTensor
description:errorDescription];
}
return tensor;
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,99 @@
// 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/TFLTensor.h"
@class TFLInterpreter;
@class TFLSignatureRunner;
NS_ASSUME_NONNULL_BEGIN
/**
* @enum TFLTensorType
* This enum specifies input or output tensor types.
*/
typedef NS_ENUM(NSUInteger, TFLTensorType) {
/** Input tensor type. */
TFLTensorTypeInput,
/** Output tensor type. */
TFLTensorTypeOutput,
};
@interface TFLTensor (Internal)
/** Input or output tensor type. */
@property(nonatomic, readonly) TFLTensorType type;
/** Index of the tensor. */
@property(nonatomic, readonly) NSUInteger index;
/** The input or output name of the tensor in the signatureDef. */
@property(nonatomic, nullable, readonly) NSString *nameInSignature;
/**
* Initializes a `TFLTensor` with the given interpreter, name, data type, and quantization
* parameters.
*
* @param interpreter Interpreter backing the tensor.
* @param type Input or output tensor type.
* @param index Index of the tensor.
* @param name Name of the tensor.
* @param dataType Data type of the tensor.
* @param quantizationParameters Quantization parameters of the tensor. `nil` if the tensor does not
* use quantization.
*
* @return A new instance of `TFLTensor` with the given name, data type, shape, and quantization
* parameters.
*/
- (instancetype)initWithInterpreter:(TFLInterpreter *)interpreter
type:(TFLTensorType)type
index:(NSUInteger)index
name:(NSString *)name
dataType:(TFLTensorDataType)dataType
quantizationParameters:(nullable TFLQuantizationParameters *)quantizationParameters;
/**
* Initializes a new `TFLTensor` instance.
*
* @param signatureRunner The signature runner backing the tensor.
* @param type Input or output tensor type.
* @param nameInSignature The input or output name of the tensor in the signatureDef.
* @param name Name of the tensor.
* @param dataType Data type of the tensor.
* @param quantizationParameters Quantization parameters of the tensor. `nil` if the tensor does not
* use quantization.
*
* @return A new instance of `TFLTensor`.
*/
- (instancetype)initWithSignatureRunner:(TFLSignatureRunner *)signatureRunner
type:(TFLTensorType)type
nameInSignature:(NSString *)nameInSignature
name:(NSString *)name
dataType:(TFLTensorDataType)dataType
quantizationParameters:
(nullable TFLQuantizationParameters *)quantizationParameters;
/**
* Returns the string name of the given input or output tensor type.
*
* @param type Input or output tensor type.
*
* @return The string name of the given input or output tensor type.
*/
+ (NSString *)stringForTensorType:(TFLTensorType)type;
@end
NS_ASSUME_NONNULL_END
+116
View File
@@ -0,0 +1,116 @@
// 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/TFLTensor.h"
#import "TFLErrorUtil.h"
#import "TFLInterpreter+Internal.h"
#import "TFLSignatureRunner+Internal.h"
#import "TFLTensor+Internal.h"
NS_ASSUME_NONNULL_BEGIN
// String names of input or output tensor types.
static NSString *const kTFLInputTensorTypeString = @"input";
static NSString *const kTFLOutputTensorTypeString = @"output";
@interface TFLTensor ()
// Redefines readonly properties.
@property(nonatomic) TFLTensorType type;
@property(nonatomic) NSUInteger index;
@property(nonatomic, nullable) NSString *nameInSignature;
@property(nonatomic, copy) NSString *name;
@property(nonatomic) TFLTensorDataType dataType;
@property(nonatomic, nullable) TFLQuantizationParameters *quantizationParameters;
/**
* The tensor data accessor that could mutate the data on the tensor. It is either an interpreter or
* a signature runner. It's a strong reference to ensure that the interpreter or the signature
* runner is never released before this tensor is released.
*
* @warning Never let the interpreter or the signature runner hold a strong reference to the tensor
* to avoid retain cycles.
*/
@property(nonatomic, strong) id<TFLTensorDataAccessor> tensorDataAccessor;
@end
@implementation TFLTensor
#pragma mark - Public
- (BOOL)copyData:(NSData *)data error:(NSError **)error {
return [self.tensorDataAccessor copyData:data toInputTensor:self error:error];
}
- (nullable NSData *)dataWithError:(NSError **)error {
return [self.tensorDataAccessor dataFromTensor:self error:error];
}
- (nullable NSArray<NSNumber *> *)shapeWithError:(NSError **)error {
return [self.tensorDataAccessor shapeOfTensor:self error:error];
}
#pragma mark - TFLTensor (Internal)
- (instancetype)initWithInterpreter:(TFLInterpreter *)interpreter
type:(TFLTensorType)type
index:(NSUInteger)index
name:(NSString *)name
dataType:(TFLTensorDataType)dataType
quantizationParameters:(nullable TFLQuantizationParameters *)quantizationParameters {
self = [super init];
if (self != nil) {
_tensorDataAccessor = interpreter;
_type = type;
_index = index;
_name = [name copy];
_dataType = dataType;
_quantizationParameters = quantizationParameters;
}
return self;
}
- (instancetype)initWithSignatureRunner:(TFLSignatureRunner *)signatureRunner
type:(TFLTensorType)type
nameInSignature:(NSString *)nameInSignature
name:(NSString *)name
dataType:(TFLTensorDataType)dataType
quantizationParameters:
(nullable TFLQuantizationParameters *)quantizationParameters {
self = [super init];
if (self != nil) {
_tensorDataAccessor = signatureRunner;
_type = type;
_nameInSignature = [nameInSignature copy];
_name = [name copy];
_dataType = dataType;
_quantizationParameters = quantizationParameters;
}
return self;
}
+ (NSString *)stringForTensorType:(TFLTensorType)type {
switch (type) {
case TFLTensorTypeInput:
return kTFLInputTensorTypeString;
case TFLTensorTypeOutput:
return kTFLOutputTensorTypeString;
}
}
@end
NS_ASSUME_NONNULL_END
@@ -0,0 +1,64 @@
// 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 <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class TFLTensor;
/** Protocol for providing and mutating data on a `TFLTensor`. */
@protocol TFLTensorDataAccessor <NSObject>
/**
* Copies the given data into the input tensor. This is allowed only before the interpreter or
* signature runner is invoked.
*
* @param data The data to set. The byte size of the data must match what's required by the input
* tensor.
* @param inputTensor The input tensor to copy data to.
* @param error An optional error parameter populated when there is an error in setting the data.
*
* @return Whether the data was copied into the input tensor at the given index successfully.
* Returns NO if an error occurred.
*/
- (BOOL)copyData:(NSData *)data toInputTensor:(TFLTensor *)inputTensor error:(NSError **)error;
/**
* Retrieves a copy of the data from the given tensor. For an output tensor, the interpreter or
* signature invocation has to complete before the data can be retrieved.
*
* @param tensor A tensor.
* @param error An optional error parameter populated when there is an error in getting the data.
*
* @return The data of the given tensor. `nil` if there is an error or data is not available.
*/
- (nullable NSData *)dataFromTensor:(TFLTensor *)tensor error:(NSError **)error;
/**
* Retrieves the shape of the given tensor, an array of positive unsigned integer(s) containing the
* size of each dimension. For example: shape of [[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]]] is
* [2, 2, 3].
*
* @param tensor An input or output tensor.
* @param error An optional error parameter populated when there is an error in retrieving the
* shape.
*
* @return The shape of the tensor. `nil` if there is an error in retrieving the shape.
*/
- (nullable NSArray<NSNumber *> *)shapeOfTensor:(TFLTensor *)tensor error:(NSError **)error;
@end
NS_ASSUME_NONNULL_END