Update TFLite iOS demo app documentation
PiperOrigin-RevId: 232318736
This commit is contained in:
parent
63a13795c2
commit
de82ac8a80
tensorflow/lite/g3doc
@ -1,9 +1,10 @@
|
||||
|
||||
# iOS Demo App
|
||||
|
||||
The TensorFlow Lite demo is a camera app that continuously classifies whatever
|
||||
it sees from your device's back camera, using a quantized MobileNet model. These
|
||||
instructions walk you through building and running the demo on an iOS device.
|
||||
This tutorial provides a simple iOS mobile application to classify images using
|
||||
the iOS device camera. In this tutorial, you will download the demo application
|
||||
from the Tensorflow repository, build it on your computer, and install it on
|
||||
your iOS Device. You will also learn how to customize the application to suit
|
||||
your requirements.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@ -30,47 +31,199 @@ instructions walk you through building and running the demo on an iOS device.
|
||||
If this is a new install, you will need to run the Xcode application once to
|
||||
agree to the license before continuing.
|
||||
|
||||
## Building the iOS Demo App
|
||||
|
||||
1. Install CocoaPods if you don't have it:
|
||||
* Install CocoaPods if you don't have it:
|
||||
|
||||
sudo gem install cocoapods
|
||||
|
||||
2. Download the model files used by the demo app (this is done from inside the
|
||||
cloned directory):
|
||||
### Step 1. Clone the TensorFlow source code
|
||||
|
||||
sh tensorflow/lite/examples/ios/download_models.sh
|
||||
First, we clone the GitHub repository on the computer in a folder to get the
|
||||
demo application.
|
||||
|
||||
3. Install the pod to generate the workspace file:
|
||||
```
|
||||
git clone https://github.com/tensorflow/tensorflow
|
||||
```
|
||||
|
||||
cd tensorflow/lite/examples/ios/camera
|
||||
pod install
|
||||
### Step 2. Download required dependencies
|
||||
|
||||
If you have installed this pod before and that command doesn't work, try
|
||||
Execute the shell script to download the model files used by the demo app (this
|
||||
is done from inside the cloned directory):
|
||||
|
||||
pod repo update
|
||||
```
|
||||
tensorflow/lite/examples/ios/download_models.sh
|
||||
```
|
||||
|
||||
At the end of this step you should have a file called
|
||||
`tflite_camera_example.xcworkspace`.
|
||||
Run the following command to install TensorFlow Lite pod:
|
||||
|
||||
4. Open the project in Xcode by typing this on the command line:
|
||||
```
|
||||
cd tensorflow/lite/examples/ios/camera
|
||||
pod install
|
||||
```
|
||||
|
||||
open tflite_camera_example.xcworkspace
|
||||
If you have installed this pod before and that command doesn't work, try
|
||||
|
||||
This launches Xcode if it isn't open already and opens the
|
||||
`tflite_camera_example` project.
|
||||
```
|
||||
pod repo update
|
||||
```
|
||||
|
||||
5. Under `Project navigator -> tflite_camera_example -> Targets ->
|
||||
tflite_camera_example -> General` change the bundle identifier by
|
||||
pre-pending your name:
|
||||
### Step 3. Build the XCode project
|
||||
|
||||

|
||||
Open the `tflite_camera_example.xcworkspace` project file generated in the last
|
||||
step:
|
||||
|
||||
6. Build and run the app in Xcode.
|
||||
```
|
||||
open tflite_camera_example.xcworkspace
|
||||
```
|
||||
|
||||
Note that as mentioned earlier, you must already have a device set up and
|
||||
linked to your Apple Developer account in order to deploy the app on a
|
||||
device.
|
||||
Under `Project navigator -> tflite_camera_example -> Targets ->
|
||||
tflite_camera_example -> General` change the bundle identifier by pre-pending
|
||||
your name:
|
||||
|
||||

|
||||
|
||||
Plug in your iOS device. Note the app must be executed with a real device with
|
||||
camera. Select the iOS device from the drop-down menu.
|
||||
|
||||

|
||||
|
||||
Click the "Run" button to build and run the app
|
||||
|
||||

|
||||
|
||||
Note that as mentioned earlier, you must already have a device set up and linked
|
||||
to your Apple Developer account in order to deploy the app on a device.
|
||||
|
||||
You'll have to grant permissions for the app to use the device's camera. Point
|
||||
the camera at various objects and enjoy seeing how the model classifies things!
|
||||
|
||||
## Understanding iOS App Code
|
||||
|
||||
### Get camera input
|
||||
|
||||
The main logic of this app is in the Objective C++ source file
|
||||
`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`.
|
||||
|
||||
The `setupAVCapture` method constructs a `AVCaptureSession` and set itself as a
|
||||
delegate. The `captureOutput:didOutputSampleBuffer:fromConnection:` method is
|
||||
called for every captured frame. It calls `runModelOnFrame` to run the model for
|
||||
every frame.
|
||||
|
||||
### Create an interpreter
|
||||
|
||||
To create the interpreter, we need to load the model file. The following code
|
||||
will load a model and create an interpreter.
|
||||
|
||||
```
|
||||
model = tflite::FlatBufferModel::BuildFromFile([graph_path UTF8String]);
|
||||
```
|
||||
|
||||
Behind the scenes, the model is loaded as a memory-mapped file. It offers faster
|
||||
load times and reduce the dirty pages in memory.
|
||||
|
||||
Construct a `BuiltinOpResolver` to use the TensorFliw Lite buildin ops. Then,
|
||||
create the interpreter object using `InterpreterBuilder` that takes the model
|
||||
file as argument as shown below.
|
||||
|
||||
```
|
||||
tflite::ops::builtin::BuiltinOpResolver resolver;
|
||||
tflite::InterpreterBuilder(*model, resolver)(&interpreter);
|
||||
```
|
||||
|
||||
### Obtain the input buffer
|
||||
|
||||
By default, the app uses quantized model since it's smaller and faster. The
|
||||
buffer is a raw pointer to an array of 8 bit unsigned integers (`uint8_t`). The
|
||||
following code obtains the input buffer from the interpreter:
|
||||
|
||||
```
|
||||
// Get the index of first input tensor.
|
||||
int input_tensor_index = interpreter->inputs()[0];
|
||||
// Get the pointer to the input buffer.
|
||||
uint8_t* buffer = interpreter->typed_tensor<uint8_t>(input_tensor_index);
|
||||
```
|
||||
|
||||
Throughout this document, it's assumed a quantized model is used.
|
||||
|
||||
### Pre-process of bitmap image
|
||||
|
||||
The MobileNet model we're using takes 224x224x3 inputs, where the dimensions are
|
||||
width, height, and colors (RGB). The images returned from `AVCaptureSession` is
|
||||
bigger, and has 4 color channels (RGBA).
|
||||
|
||||
Many image classification models (like MobileNet) take fixe-sized inputs. It's
|
||||
required to scale or crop the image before feeding it into the model, and change
|
||||
the channels from RGBA to RGB.
|
||||
|
||||
The code to pre-process the images is in `ProcessInputWithQuantizedModel`
|
||||
function in
|
||||
`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`. It's a
|
||||
simple implementation for nearest neighbor color sampling, and it only copies
|
||||
the first 3 bytes for each pixel.
|
||||
|
||||
```
|
||||
void ProcessInputWithQuantizedModel(
|
||||
uint8_t* input, uint8_t* output, int image_width, int image_height, int image_channels) {
|
||||
for (int y = 0; y < wanted_input_height; ++y) {
|
||||
uint8_t* out_row = output + (y * wanted_input_width * wanted_input_channels);
|
||||
for (int x = 0; x < wanted_input_width; ++x) {
|
||||
const int in_x = (y * image_width) / wanted_input_width;
|
||||
const int in_y = (x * image_height) / wanted_input_height;
|
||||
uint8_t* in_pixel = input + (in_y * image_width * image_channels) + (in_x * image_channels);
|
||||
uint8_t* out_pixel = out_row + (x * wanted_input_channels);
|
||||
for (int c = 0; c < wanted_input_channels; ++c) {
|
||||
out_pixel[c] = in_pixel[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note the code is preprocessing and preparing the model input from the camera
|
||||
data. Therefore the first parameter `input` should be the camera buffer. The
|
||||
second parameter `output` should be the buffer of model input.
|
||||
|
||||
### Run inference and obtain output buffer
|
||||
|
||||
After preprocessing and filling the data into the input buffer of the
|
||||
interpreter, it's really easy to run the interpreter:
|
||||
|
||||
```
|
||||
if (interpreter->Invoke() != kTfLiteOk) {
|
||||
NSLog("Failed to invoke!");
|
||||
}
|
||||
```
|
||||
|
||||
The result is stored in the output tensor buffer of the interpreter. The
|
||||
following code obtains the pointer to the buffer:
|
||||
|
||||
```
|
||||
// Get the index of first output tensor.
|
||||
const int output_tensor_index = interpreter->outputs()[0];
|
||||
// Get the pointer to the output buffer.
|
||||
uint8_t* buffer = interpreter->typed_tensor<uint8_t>(output_tensor_index);
|
||||
```
|
||||
|
||||
### Post-process values
|
||||
|
||||
The output buffer contains an array of `uint8_t`, and the value range is 0-255.
|
||||
We need to convert the value to float to get the probabilities with value range
|
||||
0.0-1.0. The formula of the quantization value mapping is:
|
||||
|
||||
float_value = (quantized_value - zero_point) * scale
|
||||
|
||||
The following code converts quantized values back to float values, using the
|
||||
quantizaiton parameters in tensors:
|
||||
|
||||
```
|
||||
uint8_t* quantized_output = interpreter->typed_output_tensor<uint8_t>(0);
|
||||
int32_t zero_point = input_tensor->params.zero_point;
|
||||
float scale = input_tensor->params.scale;
|
||||
float output[output_size];
|
||||
for (int i = 0; i < output_size; ++i) {
|
||||
output[i] = (quantized_output[i] - zero_point) * scale;
|
||||
}
|
||||
```
|
||||
|
||||
Finally, we find the best set of classifications by storing them in a priority
|
||||
queue based on their confidence scores. See the `GetTopN` function in
|
||||
`tensorflow/lite/examples/ios/camera/CameraExampleViewController.mm`.
|
||||
|
BIN
tensorflow/lite/g3doc/images/ios/build_and_execute.png
Normal file
BIN
tensorflow/lite/g3doc/images/ios/build_and_execute.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 79 KiB |
BIN
tensorflow/lite/g3doc/images/ios/device_selection.png
Normal file
BIN
tensorflow/lite/g3doc/images/ios/device_selection.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 117 KiB |
Loading…
Reference in New Issue
Block a user