目录
导出模型
设置你的树莓派
在Raspberry Pi上启用实时对象检测
概括
在这里,我们下载了一份经过训练的模型以供离线使用。然后,我们展示了如何编写一个简单的Python应用程序,该应用程序可以每秒多次从相机中提取图像,运行模型,并确定行人是否已进入视野。
这个由三部分组成的文章系列探讨了如何训练、测试和部署AI模型,以使用Azure自定义视觉检测车辆前方的行人。
上一篇文章测试、重新训练和重新测试了一个对象检测模型。但是,如果没有最终部署,它的用途有限。
本文将介绍下载训练模型的副本以供离线使用。它还将演示如何将模型部署到Raspberry Pi并对其进行修改以充当实时对象检测器。
访问GitHub以获取此演示的完整代码。
导出模型本系列上一篇文章对模型进行了多次测试并迭代以提高模型的性能。现在,是时候导出模型并离线运行了。
在自定义视觉服务门户网站中选择您的项目。移至项目的Performance选项卡,选择要导出的迭代,然后单击顶部菜单栏上的Export 。
下一页会提示您选择平台。选择Dockerfile,因为您将在边缘设备上运行模型。
下一步是指定运行模型的平台类型。从菜单中选择ARM (Raspberry Pi 3) ,然后单击导出。然后,单击下载。
上述选项下载一个.zip文件,其中包含在Raspberry Pi设备上运行模型的现成解决方案。
现在模型已准备好离线运行,我们将设置Raspberry Pi来托管服务。
设置你的树莓派本文假设您的设备使用Raspberry Pi操作系统(OS)。如果没有,请按照Raspberry Pi的入门指南在您的设备上安装操作系统。安装操作系统后,安装其他必需的包以运行对象检测模型。
注意:我们在Raspberry Pi 4 Model B上使用Debian Buster(现在称为Raspberry Pi Legacy OS)和使用Python 3.7的Raspberry Pi Camera V2测试了本文的设置和代码。但是,该代码应适用于任何版本的操作系统、相机和所需模块。
在安装所需模块之前,请使用以下命令更新所有软件包:
$ sudo apt-get update && sudo apt-get upgrade
您应该创建一个虚拟环境来安装所需的模块。创建并激活一个虚拟环境,名称env如下:
$ python3 -m venv env
$ source env/bin/activate
激活虚拟环境后,安装所需的软件包。自定义视觉模型需要边缘设备上的 TensorFlow。
执行以下命令安装TensorFlow 2.4.0和Python 3.7。
$ pip install https://github.com/bitsy-ai/tensorflow-arm-bin/releases/download/v2.4.0-rc2/tensorflow-2.4.0rc2-cp37-none-linux_armv7l.whl
然后安装一个Pillow库来支持打开、操作和保存图像。
$ pip install pillow
最后,安装Flask来运行服务器。
$ pip install flask
安装上述模块后,您的环境就可以托管自定义视觉模型了。
接下来,在Raspberry Pi上运行您的自定义视觉模型。之前导出的训练模型是.zip格式,应该很容易带到Raspberry Pi中。
在您的 Raspberry Pi 上解压缩导出的模型并转到应用程序目录。此目录包含经过训练的模型、标签和Flask应用程序文件以处理图像预测。
首先,检查predict.py文件:
import tensorflow as tf
import numpy as np
import PIL.Image
from datetime import datetime
from urllib.request import urlopen
MODEL_FILENAME = 'model.pb'
LABELS_FILENAME = 'labels.txt'
od_model = None
labels = None
class ObjectDetection:
INPUT_TENSOR_NAME = 'image_tensor:0'
OUTPUT_TENSOR_NAMES = ['detected_boxes:0', 'detected_scores:0', 'detected_classes:0']
def __init__(self, model_filename):
graph_def = tf.compat.v1.GraphDef()
with open(model_filename, 'rb') as f:
graph_def.ParseFromString(f.read())
self.graph = tf.Graph()
with self.graph.as_default():
tf.import_graph_def(graph_def, name='')
# Get input shape
with tf.compat.v1.Session(graph=self.graph) as sess:
self.input_shape = sess.graph.get_tensor_by_name(self.INPUT_TENSOR_NAME).shape.as_list()[1:3]
def predict_image(self, image):
image = image.convert('RGB') if image.mode != 'RGB' else image
image = image.resize(self.input_shape)
inputs = np.array(image, dtype=np.float32)[np.newaxis, :, :, :]
with tf.compat.v1.Session(graph=self.graph) as sess:
output_tensors = [sess.graph.get_tensor_by_name(n) for n in self.OUTPUT_TENSOR_NAMES]
outputs = sess.run(output_tensors, {self.INPUT_TENSOR_NAME: inputs})
return outputs
def initialize():
global od_model
od_model = ObjectDetection(MODEL_FILENAME)
global labels
with open(LABELS_FILENAME) as f:
labels = [l.strip() for l in f.readlines()]
def predict_url(image_url):
with urlopen(image_url) as binary:
image = PIL.Image.open(binary)
return predict_image(image)
def predict_image(image):
predictions = od_model.predict_image(image)
predictions = [{'probability': round(float(p[1]), 8),
'tagId': int(p[2]),
'tagName': labels[p[2]],
'boundingBox': {
'left': round(float(p[0][0]), 8),
'top': round(float(p[0][1]), 8),
'width': round(float(p[0][2] - p[0][0]), 8),
'height': round(float(p[0][3] - p[0][1]), 8)
}
} for p in zip(*predictions)]
response = {'id': '', 'project': '', 'iteration': '', 'created': datetime.utcnow().isoformat(),
'predictions': predictions}
print("Results: " + str(response))
return response
上面的代码定义了以下方法:
- ObjectDetection类加载训练好的模型。该ObjectDetection类还定义了一个将图像作为输入名为predict_image的方法,使用模型对其进行评分,并返回预测。
- initialize方法创建ObjectDetection类的对象并从指定的标签文件加载标签。
- predict_url方法将图像URL作为参数,从指定的URL加载图像,并返回对该predict_image方法的调用。
- predict_image方法将图像文件作为参数并调用ObjectDetection类的predict_image方法。它将返回的响应保存在predictions变量中,并在屏幕上分别显示probability、tagId、tagName和boundingBox。
现在,检查app.py文件:
import json
import os
import io
# Imports for the REST API
from flask import Flask, request, jsonify
# Imports for image processing
from PIL import Image
# Imports for prediction
from predict import initialize, predict_image, predict_url
app = Flask(__name__)
# 4MB Max image size limit
app.config['MAX_CONTENT_LENGTH'] = 4 * 1024 * 1024
# Default route just shows simple text
@app.route('/')
def index():
return 'CustomVision.ai model host harness'
# Like the CustomVision.ai Prediction service /image route handles either
# - octet-stream image file
# - a multipart/form-data with files in the imageData parameter
@app.route('/image', methods=['POST'])
@app.route('//image', methods=['POST'])
@app.route('//image/nostore', methods=['POST'])
@app.route('//classify/iterations//image', methods=['POST'])
@app.route('//classify/iterations//image/nostore', methods=['POST'])
@app.route('//detect/iterations//image', methods=['POST'])
@app.route('//detect/iterations//image/nostore', methods=['POST'])
def predict_image_handler(project=None, publishedName=None):
try:
imageData = None
if ('imageData' in request.files):
imageData = request.files['imageData']
elif ('imageData' in request.form):
imageData = request.form['imageData']
else:
imageData = io.BytesIO(request.get_data())
img = Image.open(imageData)
results = predict_image(img)
return jsonify(results)
except Exception as e:
print('EXCEPTION:', str(e))
return 'Error processing image', 500
# Like the CustomVision.ai Prediction service /url route handles url's
# in the body of hte request of the form:
# { 'Url': ''}
@app.route('/url', methods=['POST'])
@app.route('//url', methods=['POST'])
@app.route('//url/nostore', methods=['POST'])
@app.route('//classify/iterations//url', methods=['POST'])
@app.route('//classify/iterations//url/nostore', methods=['POST'])
@app.route('//detect/iterations//url', methods=['POST'])
@app.route('//detect/iterations//url/nostore', methods=['POST'])
def predict_url_handler(project=None, publishedName=None):
try:
image_url = json.loads(request.get_data().decode('utf-8'))['url']
results = predict_url(image_url)
return jsonify(results)
except Exception as e:
print('EXCEPTION:', str(e))
return 'Error processing image'
if __name__ == '__main__':
# Load and intialize the model
initialize()
# Run the server
app.run(host='0.0.0.0', port=80)
上面的代码为对象检测模型创建了一个Flask rest API。它定义了两个方法:predict_image_handler和predict_url_handler,应用程序根据预测是针对图像文件还是图像文件URL来调用它们。
在探索模型如何离线运行之后,运行应用程序。
首先,将app.py文件中的主机和端口更改如下:
# Run the server
app.run(host='127.0.0.1', port=5000)
使用此修改保存文件并运行应用程序:
$ python app.py
让服务器保持运行。打开另一个终端并使用以下curl命令向服务器发送请求:
$ curl -X POST http://127.0.0.1:5000/url -d '{ "url": "" }'
上述命令调用Prediction API,预测将出现在您的屏幕上。
该模型现在离线运行,可以检测图像中何时何地出现人。但是,该模型目前仅适用于静止图像。它必须能够立即确定行人是否已进入视野。
要捕获视频流、提取其图像、通过模型运行它们并检测人的存在,您需要在Raspberry Pi上安装OpenCV。该库应启用实时对象检测。
使用以下命令安装OpenCV:
$ pip install opencv-python
一旦OpenCV成功安装,实时物体检测器就在几步之遥。
注意:在继续之前,请测试您的相机模块。您可以使用以下命令尝试Raspberry Pi Camera V2:
$ raspistill –o output.jpg
如果您使用的是其他相机,请确保它与Raspberry Pi兼容并且可以捕获图像和视频。否则,程序会触发错误。
现在,在您的应用目录中创建另一个名为walker-detection.py的文件并添加以下代码:
import cv2
# Imports for image processing
from PIL import Image
# Imports for prediction
from predict import initialize, predict_image
def main():
# Load and initialize the model
initialize()
# create a video capture object
capture = cv2.VideoCapture(0)
while(True):
# capture the video frame by frame
ret, frame = capture.read()
# pass the frame for detection
predictions = predict_image(Image.fromarray(frame))
# display the frame
cv2.imshow('Pedestrian detector', frame)
# define quitting button
keyCode = cv2.waitKey(30) & 0xFF
if keyCode == 27:
break
# release the object once the loop is over
capture.release()
# destroy all windows
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
上面的程序首先加载和初始化模型。接下来,它创建一个对象捕获函数来捕获视频。然后,它读取每一帧并将帧传递给predict_image方法,用于预测和显示帧。它还定义了密钥,以防它必须打破循环。最后,一旦循环结束,它会释放视频捕获并销毁所有窗口。
现在,运行程序如下:
$ python pedestrian-detection.py
程序成功运行后,将打开一个包含当前相机字段的单独窗口,您将在终端中看到预测。
如果当前视野为空,您的模型将返回一个空的预测列表。
本文演示了如何在边缘部署模型以进行实时预测。自定义视觉服务支持训练和部署复杂的机器学习模型,而无需全面了解底层AI和算法。
本系列文章是Azure自定义视觉服务的介绍性指南。Custom Vision服务使广泛的开发人员能够训练和部署专门针对其用例量身定制的机器学习模型。
既然您知道它有多么简单,请查看Azure的自定义视觉服务,以了解有关训练和部署机器学习模型的更多信息。
要了解如何通过更快的AI方法推动应用程序创新并获得持久的业务收益,请查看Forrester研究:通过专业云AI服务推动应用程序创新。
https://www.codeproject.com/Articles/5326983/Training-a-Custom-Object-Detection-Model-on-Azur-3