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,37 @@
load("@bazel_skylib//rules:build_test.bzl", "build_test")
load("@build_bazel_rules_apple//apple:ios.bzl", "ios_static_framework")
load("//tensorflow/lite/ios:ios.bzl", "TFL_MINIMUM_OS_VERSION")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:license"],
licenses = ["notice"],
)
# Main target for the inference diff tool iOS framework.
# bazel build --config=ios_arm64 -c opt --cxxopt=-std=c++17 //tensorflow/lite/tools/evaluation/tasks/ios:TensorFlowLiteInferenceDiffC_framework
ios_static_framework(
name = "TensorFlowLiteInferenceDiffC_framework",
hdrs = [
"//tensorflow/lite/tools:logging.h",
"//tensorflow/lite/tools/evaluation/tasks:task_executor_c_api.h",
],
bundle_name = "TensorFlowLiteInferenceDiffC",
minimum_os_version = TFL_MINIMUM_OS_VERSION,
deps = [
"//tensorflow/lite/tools/evaluation/tasks:task_executor_c_api",
"//tensorflow/lite/tools/evaluation/tasks/inference_diff:run_eval_lib",
],
)
# Used for building TensorFlowLiteInferenceDiffC_framework framework.
build_test(
name = "framework_build_test",
# build_test targets are not meant to be run with sanitizers.
tags = [
"nomsan",
"notsan",
],
targets = [
":TensorFlowLiteInferenceDiffC_framework",
],
)
@@ -0,0 +1,43 @@
# TFLite iOS evaluation app.
## Description
An iOS app to evaluate TFLite models. This is mainly for running different
evaluation tasks on iOS. Right now it only supports evaluating the inference
difference between cpu and delegates.
The app reads evaluation parameters from a JSON file named
`evaluation_params.json` in its `evaluation_data` directory. Any downloaded
models for evaluation should also be placed in `evaluation_data` directory.
The JSON file specifies the name of the model file and other evaluation
parameters like number of iterations, number of threads, delegate name. The
default values in the JSON file are for the Mobilenet_v2_1.0_224 model
([tflite&pb][mobilenet-model]).
## Building / running the app
* Follow the [iOS build instructions][build-ios] to configure the Bazel
workspace and `.bazelrc` file correctly.
* Run `build_evaluation_framework.sh` script to build the evaluation
framework. This script will build the evaluation framework targeting iOS
arm64 and put it under `TFLiteEvaluation/TFLiteEvaluation/Frameworks`
directory.
* Update evaluation parameters in `evaluation_params.json`.
* Change `Build Phases -> Copy Bundle Resources` and add the model file to the
resources that need to be copied.
* Ensure that `Build Phases -> Link Binary With Library` contains the
`Accelerate framework` and `TensorFlowLiteInferenceDiffC.framework`.
* Now try running the app. The app has a single button that runs the
evaluation on the model and displays results in a text view below. You can
also see the console output section in your Xcode to see more detailed
information.
[build-ios]: https://tensorflow.org/lite/guide/build_ios
[mobilenet-model]: https://github.com/tensorflow/tflite-support/raw/master/tensorflow_lite_support/metadata/python/tests/testdata/image_classifier/mobilenet_v2_1.0_224.tflite
[mobilenet-paper]: https://arxiv.org/pdf/1704.04861.pdf
@@ -0,0 +1,22 @@
// Copyright 2022 The TensorFlow Authors. 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 <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property(strong, nonatomic) UIWindow *window;
@end
@@ -0,0 +1,27 @@
// Copyright 2022 The TensorFlow Authors. 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 "AppDelegate.h"
@interface AppDelegate ()
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
@end
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,98 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Evaluation View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="EvaluationViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" misplaced="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="j0O-Lq-1tJ">
<rect key="frame" x="64" y="97" width="286" height="63"/>
<constraints>
<constraint firstAttribute="height" constant="63" id="8VO-Ln-L2h"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="24"/>
<state key="normal" title="Evaluate model"/>
<connections>
<action selector="onEvaluateModel:" destination="BYZ-38-t0r" eventType="touchUpInside" id="Rb1-hs-Mub"/>
</connections>
</button>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Vd4-Gf-qKO">
<rect key="frame" x="26" y="177" width="368" height="641"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="Vd4-Gf-qKO" firstAttribute="top" secondItem="j0O-Lq-1tJ" secondAttribute="bottom" constant="18" id="Kd3-pP-C1k"/>
<constraint firstItem="j0O-Lq-1tJ" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="QJU-cq-L87"/>
<constraint firstItem="Vd4-Gf-qKO" firstAttribute="trailing" secondItem="8bC-Xf-vdC" secondAttribute="trailingMargin" id="Tew-W4-Vq5"/>
<constraint firstItem="j0O-Lq-1tJ" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="Uce-n7-kZI"/>
<constraint firstItem="j0O-Lq-1tJ" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="64" id="Uhq-Rw-NKT"/>
<constraint firstItem="Vd4-Gf-qKO" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="26" id="aXc-6M-kyL"/>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="Vd4-Gf-qKO" secondAttribute="bottom" constant="10" id="tz5-wP-LZs"/>
</constraints>
</view>
<connections>
<outlet property="resultsView" destination="Vd4-Gf-qKO" id="dBT-f6-SYw"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="140" y="122.78860569715144"/>
</scene>
</scenes>
</document>
@@ -0,0 +1,22 @@
// Copyright 2022 The TensorFlow Authors. 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 <UIKit/UIKit.h>
@interface EvaluationViewController : UIViewController
@property(weak, nonatomic) IBOutlet UITextView *resultsView;
@end
@@ -0,0 +1,141 @@
// Copyright 2022 The TensorFlow Authors. 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 "EvaluationViewController.h"
#import <algorithm>
#include <fstream>
#import <sstream>
#import <string>
#import <vector>
#import <TensorFlowLiteInferenceDiffC/TensorFlowLiteInferenceDiffC.h>
namespace {
NSString* const kDocumentsPrefix = @"/Documents/";
NSString* const kModelFileKey = @"model_file";
NSString* const kOutputFilePathKey = @"output_file_path";
NSString* FilePathForResourceName(NSString* filename) {
NSString* name = [filename stringByDeletingPathExtension];
NSString* extension = [filename pathExtension];
NSString* file_path = [[NSBundle mainBundle] pathForResource:name ofType:extension];
if (file_path == NULL) {
TFLITE_LOG(FATAL) << "Couldn't find '" << [name UTF8String] << "." << [extension UTF8String]
<< "' in bundle.";
}
return file_path;
}
NSDictionary* ParseEvaluationParamsJson() {
NSString* params_json_path = FilePathForResourceName(@"evaluation_params.json");
NSData* data = [NSData dataWithContentsOfFile:params_json_path];
NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
return dict;
}
std::string FormatCommandLineParam(NSString* key, NSString* value) {
std::ostringstream stream;
stream << "--" << [key UTF8String] << "=" << [value UTF8String];
return stream.str();
}
// Reads the |evaluation_params.json| to read command line parameters and returns them as a vector
// of strings.
// Returns the evaluation parameters as key-value pairs.
void ReadCommandLineParameters(std::vector<std::string>* params) {
NSDictionary* param_dict = ParseEvaluationParamsJson();
for (NSString* key in param_dict) {
NSString* value = param_dict[key];
if ([key isEqualToString:kModelFileKey]) {
value = FilePathForResourceName(value);
}
if ([key isEqualToString:kOutputFilePathKey]) {
if (![value hasPrefix:kDocumentsPrefix]) {
TFLITE_LOG(FATAL) << "Output file must be under the Document directory";
}
// Replace the prefix "/Documents/" with the actual documents path on the device.
NSString* documents = [NSSearchPathForDirectoriesInDomains(
NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* relpath = [value substringFromIndex:[kDocumentsPrefix length]];
value = [documents stringByAppendingPathComponent:relpath];
// Create the output directory if necessary.
NSString* path = value.stringByDeletingLastPathComponent;
if (![[NSFileManager defaultManager] createDirectoryAtPath:path
withIntermediateDirectories:YES
attributes:nil
error:nil]) {
TFLITE_LOG(FATAL) << "Cannot create output directory: " << [path UTF8String];
}
// Create the output file.
std::string output_file_path_ = std::string([value UTF8String]);
std::unique_ptr<std::ofstream> output_file_ =
std::make_unique<std::ofstream>(output_file_path_, std::ios::out | std::ios::binary);
if (!output_file_->is_open()) {
TFLITE_LOG(ERROR) << "Cannot open output file: " << output_file_path_;
} else {
TFLITE_LOG(INFO) << "Create output file: " << output_file_path_;
}
}
params->push_back(FormatCommandLineParam(key, value));
}
}
std::vector<char*> StringVecToCharPtrVec(const std::vector<std::string>& str_vec) {
std::vector<char*> charptr_vec;
std::transform(str_vec.begin(), str_vec.end(), std::back_inserter(charptr_vec),
[](const std::string& s) -> char* { return const_cast<char*>(s.c_str()); });
return charptr_vec;
}
std::string EvaluationMetricsToString(TfLiteEvaluationMetrics* metrics) {
std::ostringstream stream;
stream << "Num evaluation runs: " << TfLiteEvaluationMetricsGetNumRuns(metrics);
TfLiteEvaluationMetricsLatency ref_latency = TfLiteEvaluationMetricsGetReferenceLatency(metrics);
stream << "\nReference run latency: avg=" << ref_latency.avg_us
<< "(us), std_dev=" << ref_latency.std_deviation_us << "(us)";
TfLiteEvaluationMetricsLatency test_latency = TfLiteEvaluationMetricsGetTestLatency(metrics);
stream << "\nTest run latency: avg=" << test_latency.avg_us
<< "(us), std_dev=" << test_latency.std_deviation_us << "(us)";
for (int i = 0; i < TfLiteEvaluationMetricsGetOutputErrorCount(metrics); ++i) {
TfLiteEvaluationMetricsAccuracy error = TfLiteEvaluationMetricsGetOutputError(metrics, i);
stream << "\nOutputDiff[" << i << "]: avg_error=" << error.avg_value
<< ", std_dev=" << error.std_deviation;
}
return stream.str();
}
TfLiteEvaluationMetrics* RunEvaluation() {
std::vector<std::string> command_line_params;
ReadCommandLineParameters(&command_line_params);
std::vector<char*> argv = StringVecToCharPtrVec(command_line_params);
int argc = static_cast<int>(argv.size());
TfLiteEvaluationTask* task = TfLiteEvaluationTaskCreate();
return TfLiteEvaluationTaskRunWithArgs(task, argc, argv.data());
}
} // namespace
@interface EvaluationViewController ()
@end
@implementation EvaluationViewController
- (IBAction)onEvaluateModel:(UIButton*)sender {
TfLiteEvaluationMetrics* metrics = RunEvaluation();
[_resultsView setText:[NSString stringWithUTF8String:EvaluationMetricsToString(metrics).c_str()]];
}
@end
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>UILaunchStoryboardName</key>
<string>Main</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>arm64</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -0,0 +1,8 @@
{
"model_file" : "mobilenet_v2_1.0_224.tflite",
"output_file_path" : "/Documents/outputs/inference_diff.txt",
"num_runs" : "50",
"num_threads" : "1",
"num_interpreter_threads" : "1",
"delegate" : "coreml"
}
@@ -0,0 +1,26 @@
// Copyright 2022 The TensorFlow Authors. 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 <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]) {
NSString* appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
@@ -0,0 +1,62 @@
#!/bin/bash
# Copyright 2022 The TensorFlow Authors. 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.
# ==============================================================================
set -e
WORKSPACE_ROOT=$(bazel info workspace 2> /dev/null)
EVALUATION_DIR=tensorflow/lite/tools/evaluation/tasks
DEST_DIR="${EVALUATION_DIR}/ios/TFLiteEvaluation/TFLiteEvaluation/Frameworks"
FRAMEWORK_TARGET=TensorFlowLiteInferenceDiffC_framework
function usage() {
echo "Usage: $(basename "$0")"
exit 1
}
function check_ios_configured() {
if [ ! -f "${WORKSPACE_ROOT}/${EVALUATION_DIR}/ios/BUILD" ]; then
echo "ERROR: Inference Diff framework BUILD file not found."
echo "Please enable iOS support by running the \"./configure\" script" \
"from the workspace root."
exit 1
fi
}
function build_framework() {
set -x
pushd "${WORKSPACE_ROOT}"
# Build the framework.
bazel build --config=ios_arm64 -c opt --cxxopt=-std=c++17 \
"//${EVALUATION_DIR}/ios:${FRAMEWORK_TARGET}"
# Get the generated framework path.
BAZEL_OUTPUT_FILE_PATH=$(bazel cquery "//${EVALUATION_DIR}/ios:${FRAMEWORK_TARGET}" --config=ios_arm64 --output=starlark --starlark:expr="' '.join([f.path for f in target.files.to_list()])")
# Copy the framework into the destination and unzip.
mkdir -p "${DEST_DIR}"
cp -f "${BAZEL_OUTPUT_FILE_PATH}" \
"${DEST_DIR}"
pushd "${DEST_DIR}"
unzip -o "${FRAMEWORK_TARGET}.zip"
rm -f "${FRAMEWORK_TARGET}.zip"
popd
popd
}
check_ios_configured
build_framework