How to run Coral Edge TPU inference using Python TensorFlow Lite API

Revision as of 14:38, 24 June 2020 by Registered User

1. Article purpose[edit source]

This article aims to describe how to run an inference on the STM32MP1 using a Google Coral EdgeTPU device and the Python TensorFlow-Lite API.

Info white.png Information
There are many ways to achieve the same result; this article aims to provide at least one simple example. You are free to explore other methods that are better adapted to your development constraints.

2. Difference between TensorFlow-Lite Python APIs[edit source]

The Artificial Intelligence expansion package X-LINUX-AI comes with two versions of TensorFlow-Lite. The first runtime version is based on the release 2.2.0 of TensorFlow and the second is runtime based on TensorFlow Lite runtime[1]1.15.2 and dedicated to Coral EdgeTPU use. This is due to the fact that TensorFlow Lite[2]2.2.0 does not support the Coral EdgeTPU runtime. The following figure explains the software structure.

The difference is that if you wish to use the TensorFlow Lite 2.2.0 you have to import the following librarie in your Python script:

      import tflite_runtime.interpreter as tflite

If you wish to run inferences on your Coral EdgeTPU device, you need to make the following call in your Python script:

      import tflite_edgetpu_runtime.interpreter as tflite

In the following paragraph, we will explore through a basic example how you can inference your models on the board using the Coral EdgeTPU device.

3. Run an inference using TensorFlow Lite Python API[edit source]

3.1. Preparing the workspace on the target[edit source]

Before running the inference make sure that your .tflite model is compiled for inferencing on the Coral EdgeTPU. Please take a look on how to Compile your custom model and send it to the board.

 cd /usr/local/ && mkdir workspace

After sending the compiled model to the workspace directory on the board, It is time to send the associated label file and the input image to the workspace so the inference could be executed. You can add as many .jpeg, .jpg and .png pictures as you wish and no mater their size. We will add some image processing operations later to make pictures fit in the size of the input model.

 scp path/to/your/compiled_model_edgetpu.tflite root@<board_ip_address>:/usr/local/workspace/models/
 scp path/to/your/label.txt root@<board_ip_address>:/usr/local/workspace/models/
 scp path/to/your/pictures root@<board_ip_address>:/usr/local/workspace/testdata/

Now that our workspace is ready with our compiled model file, label file and some sample pictures, it is time to see how to run an inference using the Python API. We follow by creating a python script that will be transferred via scp command and ran on the target board. This is a very basic example that executes an inference on the Coral Edge TPU that classify images.

 gedit classify_on_stm32mp1.py

3.2. Instantiating the Tensorflow Lite Interpreter[edit source]

In order to run an inference on Tensorflow Lite, we have to import the Tflite runtime and instantiate an interpreter using the interpreter class [3] given in the Python API. We will be needing also the Image librarie from PIL (Pillow). The time librarie will also be imported to test the time performance of our inference and finally OpenCV to allow image processing and image displaying. The libraries os and random will be useful in loading the input image.

      import numpy as np
      import tflite_edgetpu_runtime.interpreter as tflite
      from PIL import Image
      import time
      import cv2
      import os

We start by loading the labels from the label file by adding these code lines:

      label_file = ""
      with open( args.label_file, 'r') as  f :
                labels = [ line.strip() for line in f.readlines() ]

It is time now to load the model and feed it to the interpreter that we will instantiate using the interpreter API [3] . In this interpreter we are calling a Tensorflow Lite delegate . It is simply an API that delegates a part or all of the graph execution to Edge TPU accelerator hardware. After calling the Edge TPU librarie inside the delegate, it is the time to allocate tensors for the graph execution through our interpreter.

     model_file = "workspace/models/your_model_edgetpu.tflite"
     interpreter = tflite.Interpreter(model_path = args.model_file, experimental_delegates = [tflite.load_delegate('libedgetpu-max.so.1.0')]) 
     interpreter.allocate_tensors()

3.3. Getting the model details and processing the image[edit source]

Now that the interpreter is ready to be fed with the input images, it is important to get the models details so we will be able to adjust the image to fit in the model.

     #Getting the model input and output details
     input_details   = interpreter.get_input_details()
     output_details = interpreter.get_output_details()
     height  = input_details[0]['shape'][1]
     width   = input_details[0]['shape'][2]

It is time to point to our image directory testdata and get images randomly so we will be able to run several image. These images will be firstly converted from BGR to RGB encoding, resized to fit the size of the model input and then get their dimensions expanded by one.

     files           = os.listdir(args.image)
     input_path = files[random.randrange(0, len(files))]
     image        = Image.open(args.image + "/" + input_path)
     nn_img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
     nn_img_rgb_resized = cv2.resize(nn_img, (width, height))
     input_data = np.expand_dims(nn_img_rgb_resized, axis=0)

3.4. Invoking the interpreter and displaying results[edit source]

Now that our input data has been processed to fit in the model input size, it is time to feed the image to interpreter input and launch the inference. We will use the time librarie to record the inference duration each time. This time gives a big idea on the Edge TPU performances compared to CPU.

     interpreter.set_tensor(input_details[0]['index'], input_data)
     start = time.perf_counter()
     interpreter.invoke()
     inference_time = time.perf_counter() - start
     print("inference time:", inference_time)
     output_details = interpreter.get_output_details()
     output_data = interpreter.get_tensor(output_details[0]['index'])
     results = np.squeeze(output_data)
     top_k = results.argsort()[-5:][::-1]
     for i in top_k:
           if self._floating_model:
               print('{0:08.6f}'.format(float(results[i] ))+":", self._labels[i])
           else:
               print('{0:08.6f}'.format(float(results[i]*100/255.0))+":", self._labels[i])
     print("\n")

We add a parser to our main function so the arguments can be read from a command line:

if __name__ == '__main__':
   # add signal to catch CRTL+C
   signal.signal(signal.SIGINT, signal.SIG_DFL)
   parser = argparse.ArgumentParser()
   parser.add_argument("-i", "--image", default="/usr/local/workspace/testdata", help="image directory with image to be classified")
   parser.add_argument("-m", "--model_file", default="/usr/local/workspace/models/mobilenet_v1_1.0_224_quant_edgetpu.tflite", help=".tflite model to be executed")
   parser.add_argument("-l", "--label_file", default="/usr/local/workspace/models/label.txt", help="name of file containing labels")
   parser.add_argument("--lib_edgetpu", default='max', choices= ['max', 'throttled'], help="Choose the version of your EdgeTPU runtime")
   parser.add_argument("--top_k", type = int, default = 5, help=" The top_k classes to show")
   args = parser.parse_args()


Now that our Python script is ready to be executed it is time to send it to the board.

 scp path/to/your/script/classify_on_stm32mp1.py root@<board_ip_address>:/usr/local/workspace/

3.5. Running the inference from the board on the Coral Edge TPU[edit source]

After booting the board and connecting it to the host PC throught an SSH protocol, we are ready to run the inference via the following command

 cd /usr/local/workspace
 python3 classify_on_stm32mp1.py

Enjoy the speed of inferences on the IA hardware accelerator.