ONNX Runtime 在 Raspberry Pi 上的 IoT 部署

了解如何使用 ONNX Runtime 和 Raspberry Pi 在边缘设备上执行图像分类,从设备摄像头获取输入并将分类结果发送到终端。

如果您之前没有配置过 Raspberry Pi,请查看 Raspberry Pi 文档来设置您的设备。

将模型部署到边缘设备有很多好处和用例。请查看我们的 IoT 教程主页上的列表。

Image of Raspberry Pi and camera.

目录

先决条件

下载源代码、机器学习模型并安装软件包

烧录 Raspberry Pi 并配置好后,就可以连接并下载源代码到您的设备了。

  • 连接到您的 Raspberry Pi 设备

在本教程中,我们使用 VNC Viewer 进行远程连接。如果您打算使用 VNC Viewer,请务必遵循 这些设置步骤来建立连接。 在 Raspberry Pi 上启用 VNC 并在您的计算机上 下载 VNC Viewer 应用后,您就可以远程访问设备了。

Image of VNC Viewer

  • 下载源代码到您的 Raspberry Pi。源代码包含运行推理所需的一切,包括来自 模型库mobilenet ONNX 模型以及 imagenet_classes.txt 类文件。

      git clone https://github.com/cassiebreviu/onnxruntime-raspberrypi.git
    
  • 导航到 onnxruntime-raspberrypi 下载位置,并使用以下命令从 requirements.txt 安装软件包。

      cd onnxruntime-raspberrypi
      pip install -r requirements.txt
    

    在本教程中,我们使用的是 Raspberry Pi 摄像头模块。我们想使用提供的 cameratest.py 脚本测试摄像头。如果您遇到摄像头无法工作的问题,运行 sudo apt update sudo apt upgrade 来更新开发板和固件。

  • 运行以下命令配置和测试摄像头。这将在当前目录下创建一个名为 test.jpg 的图像捕获文件,并打开摄像头输出的实时视频流。按 ESC 键退出实时视频输出。

      python cameratest.py
    
  • cameratest.py 脚本如下供参考

      import numpy as np
      import cv2
    
      # Create test image using opencv.
      cap = cv2.VideoCapture(0)
      cap.set(3,640) # set Width
      cap.set(4,480) # set Height
    
      ret, frame = cap.read()
      frame = cv2.flip(frame, -1) # Flip camera vertically
      cv2.imwrite('test.jpg', frame)
        
      # Start live video feed until `ESC` is pressed to quit.
      while(True):
          ret, frame = cap.read()
          frame = cv2.flip(frame, -1) # Flip camera vertically
          gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            
          cv2.imshow('frame', frame)
          cv2.imshow('gray', gray)
            
          k = cv2.waitKey(30) & 0xff
          if k == 27: # press 'ESC' to quit
              break
    
      cap.release()
      cv2.destroyAllWindows()
    

    使用 inference_mobilenet.py 脚本在 Raspberry Pi 上运行推理

现在我们已经验证了摄像头在 Raspberry Pi 上连接并正常工作,是时候对源代码中提供的 ONNX 模型进行推理了。该模型是一个 MobileNet 模型,可对 1000 个类别进行图像分类。

  • 使用以下命令运行推理脚本。
      python inference_mobilenet.py
    
  • 终端输出:VNC Viewer 图像
  • 在 Raspberry Pi 上进行推理的图像:VNC Viewer 图像

  • inference_mobilenet.py 脚本如下供参考

      # Import the packages.
      from PIL import Image
      import numpy as np
      import onnxruntime
      import torch
      import cv2
    
      def preprocess_image(image_path, height, width, channels=3):
          image = Image.open(image_path)
          image = image.resize((width, height), Image.LANCZOS)
          image_data = np.asarray(image).astype(np.float32)
          image_data = image_data.transpose([2, 0, 1]) # transpose to CHW
          mean = np.array([0.079, 0.05, 0]) + 0.406
          std = np.array([0.005, 0, 0.001]) + 0.224
          for channel in range(image_data.shape[0]):
              image_data[channel, :, :] = (image_data[channel, :, :] / 255 - mean[channel]) / std[channel]
          image_data = np.expand_dims(image_data, 0)
          return image_data
    
      def softmax(x):
          """Compute softmax values for each sets of scores in x."""
          e_x = np.exp(x - np.max(x))
          return e_x / e_x.sum()
    
      def run_sample(session, image_file, categories):
          output = session.run([], {'input':preprocess_image(image_file, 224, 224)})[0]
          output = output.flatten()
          output = softmax(output) # this is optional
          top5_catid = np.argsort(-output)[:5]
          for catid in top5_catid:
              print(categories[catid], output[catid])
          # Write the result to a file.
          with open("result.txt", "w") as f:
              for catid in top5_catid:
                  f.write(categories[catid] + " " + str(output[catid]) + " \r")
    
      # Create main function to run inference.
      if __name__ == "__main__":
          # Read the categories from the classes file.
          with open("imagenet_classes.txt", "r") as f:
              categories = [s.strip() for s in f.readlines()]
            
          # Create Inference Session
          session = onnxruntime.InferenceSession("mobilenet_v2_float.onnx")
    
          # Get image from the camera.
          cap = cv2.VideoCapture(0)
          cap.set(3,640) # set Width
          cap.set(4,480) # set Height
    
          ret, frame = cap.read()
          frame = cv2.flip(frame, -1) # Flip camera vertically
          cv2.imwrite('capture.jpg', frame)
          cap.release()
          cv2.destroyAllWindows()
    
          # Run inference
          run_sample(session, 'capture.jpg', categories)
    

结论

既然我们已经在 Raspberry Pi 上成功运行了推理,我们可以使用相同的代码在任何支持 ONNX Runtime 的设备上运行推理。我们还可以使用相同的代码在 Raspberry Pi 上运行不同的模型。请查看 ONNX 模型库 中的其他模型。

更多示例