Update TFLite iOS demo app documentation

PiperOrigin-RevId: 232318736
This commit is contained in:
Yu-Cheng Ling 2019-02-04 10:13:13 -08:00 committed by TensorFlower Gardener
parent 63a13795c2
commit de82ac8a80
3 changed files with 182 additions and 29 deletions

View File

@ -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
![pre-pend your name to the bundle identifier](images/ios/bundle_identifier.png)
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:
![pre-pend your name to the bundle identifier](images/ios/bundle_identifier.png)
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.
![Device selection](images/ios/device_selection.png)
Click the "Run" button to build and run the app
![Build and execute](images/ios/build_and_execute.png)
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`.

Binary file not shown.

After

(image error) Size: 79 KiB

Binary file not shown.

After

(image error) Size: 117 KiB