在机器学习开发过程中,当模型训练好后,接下来就要进行模型推理了,根据部署环境可分为三类场景:
边缘计算:一般指手机,嵌入式设备,直接在数据生成的设备上进行推理,因为能避免将采集到的数据上传到云端,所以实时性非常好。
端计算:介于云和边缘设备之间的计算平台,个人PC可以归为这一类。
云计算:指云计算平台,具有强大的计算和存储能力,通过服务释放AI能力。
在之前跟大家分享的AI工具中,都是在PC上进行推理,也就是属于端设备推理。
基于深度学习的抠图工具
https://github.com/AIDajiangtang
基于深度学习的图像拼接工具
https://github.com/AIDajiangtang/Superpoint-LightGlue-Image-Stiching
基于大模型的分割工具
https://github.com/AIDajiangtang/Segment-Anything-CPP
https://github.com/AIDajiangtang/Segment-Anything-CSharp
今天,我将为大家演示如何在边缘设备上进行推理。
要准备毕业设计的小伙伴可以作为参考。
我选择的边缘设备是树莓派的Zero w开发板,硬件配置参数如下:
1GHz single-core CPU ARM11 ARMv6
512MB RAM
Mini HDMI® port
Micro USB OTG port
Micro USB power
HAT-compatible 40-pin header
Composite video and reset headers
CSI camera connector (v1.3 only)
这里多说一点,对于ARM芯片,要区分芯片系列与CPU架构。不同的CPU架构对应不同的指令集,如果涉及从源码编译需要考虑CPU架构。
ARM7:
时间点:ARM7系列处理器于1994年发布。
特点:ARM7系列处理器是ARM架构的早期版本,采用32位RISC架构,主要用于嵌入式系统和低功耗设备。它具有较低的功耗和成本,适用于资源受限的应用。
CPU架构:ARMv4T架构。
ARM9:
时间点:ARM9系列处理器于1997年发布。
特点:ARM9系列处理器也是基于32位RISC架构,用于多种应用,包括嵌入式系统、移动设备和数字音频。它具有较高的性能和灵活性,适用于中等功耗和性能需求的应用。
CPU架构:ARMv5TE架构。
ARM11:
时间点:ARM11系列处理器于2002年发布。
特点:ARM11系列处理器同样采用32位RISC架构,主要应用于移动设备和数字媒体领域。它具有更高的性能和计算能力,支持多媒体处理和浮点运算。
CPU架构:ARMv6架构。
ARM Cortex-A:
时间点:ARM Cortex-A系列处理器于2005年发布。
特点:Cortex-A系列面向高性能应用,用于智能手机、平板电脑、服务器和其他需要较高处理性能的设备。它具有更强大的处理能力、更高的频率和更复杂的功能。
CPU架构:基于ARMv7-A或ARMv8-A架构。
ARM Cortex-R:
时间点:ARM Cortex-R系列处理器于2004年发布。
特点:Cortex-R系列面向实时应用,用于嵌入式系统、汽车电子、工业控制等需要快速响应和可靠性的应用。它具有较低的延迟和更可靠的实时性能。
CPU架构:基于ARMv7-R或ARMv8-R架构。
ARM Cortex-M:
时间点:ARM Cortex-M系列处理器于2004年发布。
特点:Cortex-M系列面向低功耗嵌入式系统,用于微控制器、传感器、物联网设备等资源受限的应用。它具有较低的功耗、小尺寸和高效的实时性能。
CPU架构:基于ARMv6-M或ARMv7-M架构。
常见ARM芯片系列和架构
我们选择的Raspberry Zero w属于ARM11系列,ARMv6 CPU架构,支持wifi。
Raspberry Pi 1 Model A/B/A+/B+:
CPU系列:ARM11系列
CPU架构:ARMv6架构
Raspberry Pi 2 Model B:
CPU系列:ARM Cortex-A系列
CPU架构:ARMv7-A架构
Raspberry Pi 3 Model B/B+:
CPU系列:ARM Cortex-A系列
CPU架构:ARMv8-A架构
Raspberry Pi 4 Model B:
CPU系列:ARM Cortex-A系列
CPU架构:ARMv8-A架构
Raspberry Pi Zero/Zero W:
CPU系列:ARM11系列
CPU架构:ARMv6架构
Raspberry Pi Compute Module 3/3+:
CPU系列:ARM Cortex-A系列
CPU架构:ARMv8-A架构
Raspberry Pi Compute Module 4:
CPU系列:ARM Cortex-A系列
CPU架构:ARMv8-A架构
常见树莓派开发板CPU型号
由于本项目涉及到的软件比较多,我帮大家整理到一起了。
关注微信公众号:人工智能大讲堂,后台回复【rsb】获取模型和所有安装包。
开始吧。
准备硬件
除了开发板外,还需要USB电源,摄像头,miscro SD卡,以及读卡器。某宝上可以买到,然后按下图连接
准备推理框架
按理讲,硬件就绪后,接下来应该安装操作系统了,为什么要先说推理框架呢?也是出于无奈啊!
我选择的推理框架是tensorflow lite,但它对于ARMv6没有现成的pip安装包,也就是没办法通过下面的命令安装推理运行时。
python3 -m pip install tflite-runtime
有两种解决方法。
第一种是安装好树莓派操作系统后自己准备编译环境,然后从源码编译tensorflow lite whl安装包。
https://www.tensorflow.org/lite/guide/build_cmake_pip
第二种则是去网上找现成的针对ARM v6架构的安装包。
我选择了第二种。
开源的力量是强大的,我在Github上真就找到了一个针对ARM v6架构的whl安装包,虽然是完整的tensorflow安装包,但可以通过导出tensorflow lite来使用推理功能。
import tensorflow as tf
interpreter = tf.lite.Interpreter(model_path=args.model_file)
安装包下载连接
https://github.com/lhelontra/tensorflow-on-arm/releases/download/v2.4.0/tensorflow-2.4.0-cp37-none-linux_armv6l.whl
这里需要注意,该pip安装包是在python3.7环境下编译的,所以树莓派开发板也要安装自带python3.7的操作系统,这也是为什么先确定推理框架的原因。
准备操作系统
接下来就要找自带python3.7的树莓派操作系统。
除了python3.7外,另一个需要考虑的因素是内存,我们本次选择的Raspberry Zero w内存只有500M,为了运行效率,选择操作系统时建议选择不带桌面的Lite版本。
对于内存比较大的开发板,则可以选择带桌面的操作系统,甚至可以选择带预装各种软件环境的操作系统。
幸好,我在Archive找到python3.7的操作系统。
操作系统下载链接
https://downloads.raspberrypi.org/raspios_lite_armhf/images/raspios_lite_armhf-2021-05-28/
下载后保存到另一台电脑硬盘中等待使用。
接下来要通过树莓派自带的工具Raspberry pi Imager将操作系统烧录到miscro sd卡中。
将sd卡放入读卡器,插到另一台电脑USB接口上。
https://www.raspberrypi.com/software/
启动刻录软件
1.选择操作系统->使用自定义镜像
2.选择SD卡
3.设置
3.1勾选设置主机名,输入主机名
3.2勾选开启SSH服务,选择使用密码登录
3.3勾选设置操作系统用户名和密码,输入用户名和密码
3.4勾选配置WIFI,设置热点名和登录密码(可以用手机热点)
4.烧录
烧录成功后,将miscro sd卡插到树莓派sd卡插槽上,连接电源就可以开机了。
远程连接树莓派
由于没有桌面环境,所以需要另一台电脑远程连接到树莓派上,此时Raspberry Zero w支持wifi就起到作用了,安装操作系统时我们会配置网络,树莓派启动后主动连接热点,另一台电脑也连接到同一个热点,就可以远程了。
通过手机热点查看树莓派IP地址。
另一台电脑连接同一个手机热点。
启动另一台电脑的Windows PowerShell。
输入ssh 树莓派用户名@树莓派IP
例如 ssh rsb@192.168.133.223,根据提示需要输入密码。
光有远程还不够,还需要能够在两个系统之间传输文件,推荐在另一台电脑中安装WinSCP。
启动WinSCP,输入树莓派主机名,用户名和密码。
安装软件
安装tensorflow
wget https://github.com/lhelontra/tensorflow-on-arm/releases/download/v2.2.0/tensorflow-2.2.0-cp37-none-linux_armv6l.whl
sudo pip3 install tensorflow-2.2.0-cp37-none-linux_armv6l.whl
安装完成后通过下面命令查看是否安装成功
python -c "import tensorflow as tf;print(tf.reduce_sum(tf.random.normal([100, 100])))"
如果报类似下面这样的错误
TypeError: Descriptors cannot not be created directly.
可以尝试通过下面命令解决
Set PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
安装OpenCV
sudo apt-get -y install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev
sudo apt-get -y install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get -y install libxvidcore-dev libx264-dev
sudo apt-get -y install qt4-dev-tools libatlas-base-dev
sudo apt-get install libgstreamer1.0-dev
sudo apt-get install libopenexr-dev
sudo apt-get install libilmbase-dev
根据环境的不同,可能有些已安装,可能还缺少其他安装包,根据情况安装。
pip3 install opencv-python==3.4.6.27
也可以把上面的版本去掉,安装最新版本。
开始推理
软硬件都准备好后,就可以开始进行推理了。
准备tflite模型
由于tensorflow lite仅支持tflite格式的模型,如果你使用其他框架训练的,需要转换成tflite格式。
由于我的目的是为了演示如何在嵌入式设备上运行推理,所以选择什么模型不重要。
我给大家准备了一个水果分类和检测的模型,关注微信公众号:人工智能大讲堂,后台回复【rsb】获取模型和前面所有安装包。
模型在model文件夹下,cls_model.tflite为分类模型,det_model.tflite为目标检测模型。
分类模型类别标签
目标检测模型类别标签
打开摄像头
树莓派开发板通过外接摄像头来拍摄图像。
sudo raspi-config
选择Interface Options—camera,选择yes,将摄像头权限开启,我们便可以使用树莓派进行摄像头拍照了。
在命令行执行如下命令测试,如果看到文件夹中新增了image.jpg文件,则代表配置成功。
raspistill -t 2000 -o image.jpg
开始推理
import tensorflow as tf
import numpy as np
import cv2
det = true//是分类还是目标检测
model_path="cls_model.tflite"
if det:
model_path="det_model.tflite"
# 加载分类tflite文件
interpreter = tf.lite.Interpreter(model_path)
interpreter.allocate_tensors()
label_id_offset = 1
# Again, uncomment this decorator if you want to run inference eagerly
def detect(interpreter, input_tensor):
"""Run detection on an input image.
Args:
interpreter: tf.lite.Interpreter
input_tensor: A [1, height, width, 3] Tensor of type tf.float32.
Note that height and width can be anything since the image will be
immediately resized according to the needs of the model within this
function.
Returns:
A dict containing 3 Tensors (`detection_boxes`, `detection_classes`,
and `detection_scores`).
"""
input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
# We use the original model for pre-processing, since the TFLite model doesn't
# include pre-processing.
preprocessed_image, shapes = detection_model.preprocess(input_tensor)
interpreter.set_tensor(input_details[0]['index'], preprocessed_image.numpy())
interpreter.invoke()
boxes = interpreter.get_tensor(output_details[0]['index'])
classes = interpreter.get_tensor(output_details[1]['index'])
scores = interpreter.get_tensor(output_details[2]['index'])
return boxes, classes, scores
# 定义摄像头
capture = cv2.VideoCapture(0)
while True:
# 拍照并预处理照片
ret, frame = capture.read()
frame = cv2.flip(frame, 1)
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
if det:
resized_image = cv2.resize(frame_rgb, (300, 300))
else:
resized_image = cv2.resize(frame_rgb, (224, 224))
resized_image = resized_image .astype(np.float32)
# 将像素值缩放到0-1范围
resized_image /= 255.0
# 将像素值缩放到-1到1范围
resized_image = (resized_image - 0.5) * 2.0
test = np.expand_dims(resized_image, axis=0)
input_tensor = tf.convert_to_tensor(test, dtype=tf.float32)
# 目标检测模型进行检测
boxes, classes, scores = detect(interpreter, input_tensor)
viz_utils.visualize_boxes_and_labels_on_image_array(
test[0],
boxes[0],
classes[0].astype(np.uint32) + label_id_offset,
scores[0],
category_index,
use_normalized_coordinates=True,
min_score_thresh=0.8)
# 呈现检测结果
frame = cv2.cvtColor(test[0], cv2.COLOR_BGR2RGB)
cv2.imshow("Object detector", frame)
c = cv2.waitKey(20)
# 如果按q键,则终止
if c == 113:
break
cv2.destroyAllWindows()
最终结果