Frank Ononye
Published

Benchmarking Edge Impulse on the MaaXBoard

Run Edge Impulse models on the MaaXBoard and see how well they perform compared to other Machine learning models!

IntermediateProtip2 hours39
Benchmarking Edge Impulse on the MaaXBoard

Things used in this project

Hardware components

MaaxBoard
Avnet MaaxBoard
×1
Avnet 5V/3A USB Type-c Power Supply
×1
32GB micro SD card
×1
Cable, USB to TTL Serial Converter 5V
Cable, USB to TTL Serial Converter 5V
×1
Ethernet Cable, 15 m
Ethernet Cable, 15 m
×1
MakerHawk TC66C USB Tester
×1

Software apps and online services

Edge Impulse Studio
Edge Impulse Studio
OpenCV
OpenCV

Story

Read more

Code

benchmark_classification.py

Python
Use this for getting the scores and inference speed on the EfficientNet model
#!/usr/bin/env python3

import tflite_runtime.interpreter as tflite
from tflite_runtime.interpreter import Interpreter

import sys
import os
import logging as log
import argparse
import subprocess
from timeit import default_timer as timer

import cv2
import numpy as np

from PIL import Image
from PIL import ImageFont, ImageDraw

# Function to draw a rectangle with width > 1
def draw_rectangle(draw, coordinates, color, width=1):
    for i in range(width):
        rect_start = (coordinates[0] - i, coordinates[1] - i)
        rect_end = (coordinates[2] + i, coordinates[3] + i)
        draw.rectangle((rect_start, rect_end), outline = color, fill = color)

# Function to read labels from text files.
def ReadLabelFile(file_path):
  with open(file_path, 'r') as f:
    return [line.strip() for line in f.readlines()]

def inference_tf(runs, image, model, label=None):
   if label:
       labels = ReadLabelFile(label)
   else:
       labels = None
   
   # Load TFLite model and allocate tensors.
   interpreter = tflite.Interpreter(model_path=model)
   interpreter.allocate_tensors()
   interpreter.invoke()
   
   # Get input and output tensors.
   input_details = interpreter.get_input_details()
   output_details = interpreter.get_output_details()
   height = input_details[0]['shape'][1]
   width = input_details[0]['shape'][2]
   floating_model = False
   if input_details[0]['dtype'] == np.float32:
       floating_model = True
   
   img = Image.open(image)
   draw = ImageDraw.Draw(img, 'RGBA')
   helvetica=ImageFont.truetype("./Helvetica.ttf", size=72)
        
   picture = cv2.imread(image)
   initial_h, initial_w, channels = picture.shape
   frame = cv2.resize(picture, (width, height))
   
   # add N dim
   input_data = np.expand_dims(frame, axis=0)
   
   if floating_model:
      input_data = (np.float32(input_data) - 127.5) / 127.5
   
   interpreter.set_tensor(input_details[0]['index'], input_data)
   
   #  Start synchronous inference and get inference result
   # Run inference.
   print("Running inferencing for ", runs, " times.")
       
   if runs == 1:
      start = timer()
      interpreter.invoke()
      end = timer()
      print('Elapsed time is ', ((end - start)/runs)*1000, 'ms' )
   else:
      start = timer()
      print('Initial run, discarding.')
      interpreter.invoke()
      end = timer()
      print('First run time is ', (end - start)*1000, 'ms')
      start = timer()
      for i in range(runs):
         interpreter.invoke()
      end = timer()
      print('Elapsed time is ', ((end - start)/runs)*1000, 'ms' )
   
   output_data = interpreter.get_tensor(output_details[0]['index'])
   results = np.squeeze(output_data)
   # Get only the top 3 results
   top_k = results.argsort()[-3:][::-1]  
   for i in top_k:
      if labels:
          print('{:08.6f}: {}'.format(float(results[i] / 255.0), labels[i]))
      else:
          print ('score = ', labels[i])

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model', help='Path of the detection model.', required=True)
    parser.add_argument('--label', help='Path of the labels file.')
    parser.add_argument('--input', help='File path of the input image.', required=True)
    parser.add_argument('--runs', help='Number of times to run the inference', type=int, default=1)
    args = parser.parse_args()
    
    if ( args.label ):
      label_file = args.label
    else:
      label_file = None
    
    result = inference_tf( args.runs, args.input, args.model, label_file)

if __name__ == '__main__':
  main()

ei_benchmark_template.py

Python
Use this for getting the scores and inference speed on your Edge Impulse model
#!/usr/bin/env python

import cv2
import os
import sys
import getopt
import numpy as np
from edge_impulse_linux.image import ImageImpulseRunner

runner = None
show_camera = True

def help():
    print('python ei_benchmark5_MaaX.py </home/root/benchmark_v3-linux-aarch64-v7.eim> </home/root/MaaXBoard_folders/test_pics/fruit.jpeg>')
    #Change the above print line but keep the same format ('.py file <.eim file path> <test image path>')

def main(argv):
    try:
        opts, args = getopt.getopt(argv, "h", ["--help"])
    except getopt.GetoptError:
        help()
        sys.exit(2)

    for opt, arg in opts:
        if opt in ('-h', '--help'):
            help()
            sys.exit()

    if len(args) < 2:
        help()
        sys.exit(2)

    model = args[0]
    test_image_path = args[1]

    #For the next 3 lines, make sure the path is correct. The path to root, then the .eim file, then the test image path.
    dir_path = "/home/root"
    modelfile = "/home/root/benchmark_v3-linux-aarch64-v7.eim"
    test_image_path_absolute = "/home/root/MaaXBoard_folders/test_pics/fruit.jpeg"

    print('MODEL:', modelfile)
    print('TEST IMAGE:', test_image_path_absolute)

    with ImageImpulseRunner(modelfile) as runner:
        try:
            model_info = runner.init()
            print('Loaded runner for "' + model_info['project']['owner'] + ' / ' + model_info['project']['name'] + '"')
            labels = model_info['model_parameters']['labels']

            img = cv2.imread(test_image_path_absolute)

            features = []

            EI_CLASSIFIER_INPUT_WIDTH = runner.dim[0]
            EI_CLASSIFIER_INPUT_HEIGHT = runner.dim[1]

            in_frame_cols = img.shape[1]
            in_frame_rows = img.shape[0]

            factor_w = EI_CLASSIFIER_INPUT_WIDTH / in_frame_cols
            factor_h = EI_CLASSIFIER_INPUT_HEIGHT / in_frame_rows

            largest_factor = factor_w if factor_w > factor_h else factor_h

            resize_size_w = int(largest_factor * in_frame_cols)
            resize_size_h = int(largest_factor * in_frame_rows)
            resize_size = (resize_size_w, resize_size_h)

            resized = cv2.resize(img, resize_size, interpolation=cv2.INTER_AREA)

            crop_x = int((resize_size_w - resize_size_h) / 2) if resize_size_w > resize_size_h else 0
            crop_y = int((resize_size_h - resize_size_w) / 2) if resize_size_h > resize_size_w else 0

            crop_region = (crop_x, crop_y, EI_CLASSIFIER_INPUT_WIDTH, EI_CLASSIFIER_INPUT_HEIGHT)

            cropped = resized[crop_region[1]:crop_region[1]+crop_region[3], crop_region[0]:crop_region[0]+crop_region[2]]

            if runner.isGrayscale:
                cropped = cv2.cvtColor(cropped, cv2.COLOR_BGR2GRAY)
                pixels = np.array(cropped).flatten().tolist()

                for p in pixels:
                    features.append((p << 16) + (p << 8) + p)
            else:
                cv2.imwrite('test.jpeg', cropped)

                pixels = np.array(cropped).flatten().tolist()

                for ix in range(0, len(pixels), 3):
                    b = pixels[ix + 0]
                    g = pixels[ix + 1]
                    r = pixels[ix + 2]
                    features.append((r << 16) + (g << 8) + b)


            # Do the feature extraction or classification here based on your model

            res = runner.classify(features)

            if "classification" in res["result"].keys():
                print('Result (%d ms.) ' % (res['timing']['dsp'] + res['timing']['classification']), end='')
                for label in labels:
                    score = res['result']['classification'][label]
                    print('%s: %.2f\t' % (label, score), end='')
                print('', flush=True)

            elif "bounding_boxes" in res["result"].keys():
                print('Found %d bounding boxes (%d ms.)' % (len(res["result"]["bounding_boxes"]), res['timing']['dsp'] + res['timing']['classification']))

                # Resize the image for display
                resized_img = cv2.resize(img, (224, 224))  # Change dimensions as needed

                # Draw bounding boxes on the resized image
                for bb in res["result"]["bounding_boxes"]:
                    label = bb['label']
                    value = bb['value']
                    x, y, w, h = bb['x'], bb['y'], bb['width'], bb['height']

                    # Debugging to check the label being processed
                    print(f"Processing label: {label}, Score: {value:.2f}")


                    # Define colors based on label
                    if label == 'banana':
                        box_color = (0, 255, 0)  # Green color for bananas
                    elif label == 'apple':
                        box_color = (0, 0, 255)  # Red color for apples
                    else:
                        box_color = (255, 0, 0)  # Default to blue for other objects

                    cv2.rectangle(resized_img, (x, y), (x + w, y + h), box_color, 2)
                    cv2.putText(resized_img, f'{label} ({value:.2f})', (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, box_color, 2)


                # Save the annotated image
                annotated_image_path = '/home/root/MaaXBoard_folders/test_pics/annotated_image.jpeg'
                cv2.imwrite(annotated_image_path, resized_img)


        finally:
            if runner:
                runner.stop()

if __name__ == "__main__":
    main(sys.argv[1:])

benchmark_tf_lite.py

Python
Use this for getting the scores and inference speed on the MobileNet models
#!/usr/bin/env python3

import tflite_runtime.interpreter as tflite
from tflite_runtime.interpreter import Interpreter


import sys
import os
import logging as log
import argparse
import subprocess
from timeit import default_timer as timer

import cv2
import numpy as np

from PIL import Image
from PIL import ImageFont, ImageDraw

# Function to draw a rectangle with width > 1
def draw_rectangle(draw, coordinates, color, width=1):
    for i in range(width):
        rect_start = (coordinates[0] - i, coordinates[1] - i)
        rect_end = (coordinates[2] + i, coordinates[3] + i)
        draw.rectangle((rect_start, rect_end), outline = color, fill = color)

# Function to read labels from text files.
def ReadLabelFile(file_path):
  with open(file_path, 'r') as f:
    lines = f.readlines()
  ret = {}
  for line in lines:
    pair = line.strip().split(maxsplit=1)
    ret[int(pair[0])] = pair[1].strip()
  return ret

def inference_tf(runs, image, model, output, label=None):
   if label:
       labels = ReadLabelFile(label)
   else:
       labels = None
   
   # Load TFLite model and allocate tensors.
   interpreter = tflite.Interpreter(model_path=model)
   interpreter.allocate_tensors()
   
   # Get input and output tensors.
   input_details = interpreter.get_input_details()
   output_details = interpreter.get_output_details()
   height = input_details[0]['shape'][1]
   width = input_details[0]['shape'][2]
   floating_model = False
   if input_details[0]['dtype'] == np.float32:
       floating_model = True
   
   img = Image.open(image)
   draw = ImageDraw.Draw(img, 'RGBA')
   helvetica=ImageFont.truetype("./Helvetica.ttf", size=72)
        
   picture = cv2.imread(image)
   initial_h, initial_w, channels = picture.shape
   frame = cv2.resize(picture, (width, height))
   
   # add N dim
   input_data = np.expand_dims(frame, axis=0)
   
   if floating_model:
      input_data = (np.float32(input_data) - 127.5) / 127.5
   
   interpreter.set_tensor(input_details[0]['index'], input_data)
   
   #  Start synchronous inference and get inference result
   # Run inference.
   print("Running inferencing for ", runs, " times.")
       
   if runs == 1:
      start = timer()
      interpreter.invoke()
      end = timer()
      print('Elapsed time is ', ((end - start)/runs)*1000, 'ms' )
   else:
      start = timer()
      print('Initial run, discarding.')
      interpreter.invoke()
      end = timer()
      print('First run time is ', (end - start)*1000, 'ms')
      start = timer()
      for i in range(runs):
         interpreter.invoke()
      end = timer()
      print('Elapsed time is ', ((end - start)/runs)*1000, 'ms' )
        
   detected_boxes = interpreter.get_tensor(output_details[0]['index'])
   detected_classes = interpreter.get_tensor(output_details[1]['index'])
   detected_scores = interpreter.get_tensor(output_details[2]['index'])
   num_boxes = interpreter.get_tensor(output_details[3]['index'])
   
   print("num_boxes:", num_boxes[0])
   print("detected boxes:", detected_boxes)
   print("detected classes:", detected_classes)
   print("detected scores:", detected_scores)
   
   for i in range(int(num_boxes)):
      top, left, bottom, right = detected_boxes[0][i]
      classId = int(detected_classes[0][i])
      score = detected_scores[0][i]
      if score > 0.5:
          xmin = left * initial_w
          ymin = bottom * initial_h
          xmax = right * initial_w
          ymax = top * initial_h
          if labels:
              print(labels[classId], 'score = ', score)
          else:
              print ('score = ', score)
          box = [xmin, ymin, xmax, ymax]
          #print( 'box = ', box )
          draw_rectangle(draw, box, (0,128,128,20), width=5)
          if labels:
             draw.text((box[0] + 20, box[1] + 20), labels[classId], fill=(255,255,255,20), font=helvetica)
   img.save(output)
   print ('Saved to ', output)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--model', help='Path of the detection model.', required=True)
    parser.add_argument('--label', help='Path of the labels file.')
    parser.add_argument('--input', help='File path of the input image.', required=True)
    parser.add_argument('--output', help='File path of the output image.')
    parser.add_argument('--runs', help='Number of times to run the inference', type=int, default=1)
    args = parser.parse_args()
    
    if ( args.output):
      output_file = args.output
    else:
      output_file = 'out.jpg'
    
    if ( args.label ):
      label_file = args.label
    else:
      label_file = None
    
    result = inference_tf( args.runs, args.input, args.model, output_file, label_file)

if __name__ == '__main__':
  main()

Credits

Frank Ononye

Frank Ononye

4 projects • 10 followers

Comments