模型部署实战:教你用笔记本电脑实现实时“口罩检测”

2020-05-15 19:37:24 浏览数 (1)

口罩检测模型很有趣,相信不少小伙伴跃跃欲试,想知道如何把训练好的口罩模型部署到服务器上吗?跟着我们的教程,只需简单几步就可轻松搞定,个人笔记本电脑就可以哦!快来体验一下吧!

最近百度飞桨在业内率先开源了口罩检测模型,并且在北京地铁实际上线。该模型能够准确地对未戴口罩以及错误佩戴口罩的情况进行识别和检测,辅助一线地铁工作人员进行防疫工作。口罩模型的上线应用,主要是借助了百度飞桨推理库Paddle Inference。之前我们已经对口罩检测模型做过报导(点击此处查看)。

本文手把手教你如何把训练好的模型部署到服务器(如果没有GPU,个人笔记本电脑也可以,方法是一样的)上,调用摄像头,实现口罩实时检测。

首先,让我们先看一个口罩检测效果。

图片中红色表示未戴口罩,绿色表示已佩戴口罩。

Why Paddle Inference?

飞桨框架的推理部署能力经过多个版本的升级迭代,形成了完善的推理库Paddle Inference。Paddle Inference功能特性丰富,性能优异。针对不同平台不同应用场景,均进行了深度的适配优化,做到高吞吐、低时延,保证了飞桨模型在服务器端即训即用,同时操作简单(不同硬件,操作流程一致),简单几步就能成功部署。支持的硬件包括X86的CPU,Nvidia的GPU。

口罩检测任务介绍

在口罩检测任务中我们会用到两个模型:第一个是用来进行人脸检测的模型,第二个是用来对人脸是否戴口罩进行分类的模型。

在本文中,首先我们通过PaddleHub下载这两个模型;然后通过Paddle Inference API部署人脸检测模型以及口罩分类模型;接着就可以使用图片检验模型效果,对模型进行测试;最后,我们将检测结果进行可视化展示。

同时,我们还提供了一个小项目,运行这个项目,程序可以启动摄像头,接着调用部署好的模型,实现实时口罩检测。

NOTE:

下载整套项目的代码,解压后运行python cam_video.py,程序会启动摄像头并进行实时口罩检测。(此程序可以在macOS,Linux,Windows服务器以及Nvidia Jetson硬件上运行,注意需要安装Paddle1.7.0及以上版本)。代码地址:

https://github.com/PaddlePaddle/Paddle-Inference-Demo/tree/master/python/mask_detection

01

准备环境

1. 准备硬件

  • 服务器一台。

可以是运行macOS,Linux,Windows的台式机或者笔记本;也可以是基于Nvidia Jetson平台的硬件。

  • 摄像头一个(可选)

如果想使用摄像头实时获取视频流并进行口罩检测,需准备一个摄像头,并插入到自己的机器上。摄像头可以是USB网络摄像头,也可以是笔记本自带的摄像头。

2. 准备Python环境

代码语言:javascript复制
$ sudo apt-get install python3.6-dev liblapack-dev  gfortran
$ sudo apt-get install libfreetype6-dev libpng-dev libjpeg-dev zlib1g-dev patchelf
$ sudo apt-get install python3-pip
$ sudo apt-get install python3-opencv
$ pip install virtualenv -i https://mirror.baidu.com/pypi/simple

3. 准备Paddle环境

创建Python虚拟环境(可选),避免对全局的环境造成影响。

代码语言:javascript复制
$ virtualenv pd_env  --python=python3.6

进入Python虚拟环境。

代码语言:javascript复制
$ source pd_env/bin/activate

安装Paddle1.7.0:

macOS,Windows,Linux可以通过https://www.paddlepaddle.org.cn/中的提示进行pip安装(使用Paddle1.7.0版本)。

代码语言:javascript复制
$ pip install paddlepaddle-gpu==1.7.1.post107

这一步会同步安装numpy,scipy,cv2等依赖库,会消耗较长的时间,请耐心等待。

NVIDIA jetson硬件通过以下命令

代码语言:javascript复制
wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/paddlepaddle_gpu-0.0.0-cp36-cp36m-linux_aarch64.wh

获取whl包,再pip安装。

代码语言:javascript复制
pip install -U paddlepaddle_gpu-0.0.0-cp36-cp36m-linux_aarch64.whl

安装后可以在shell中运行Python,通过import paddle测试是否安装成功。

02

通过PaddleHub下载模型

代码语言:javascript复制
import paddlehub as hub
pyramidbox_lite_mobile_mask = hub.Module(name="pyramidbox_lite_mobile_mask")
# 将模型保存在test_program文件夹之中
pyramidbox_lite_mobile_mask.processor.save_inference_model(dirname="test_program")

PaddleHub是飞桨的预训练模型应用工具,通过以上命令,可以获得人脸检测和口罩佩戴判断分类模型,分别存储在pyramidbox_lite和mask_detector之中。文件夹中的__model__是模型结构文件,__params__文件是权重文件。

03

部署模型

1. 使用Paddle Inference API定义推理类

使用Paddle Inference API进行推理的包含以下几个部分:

1)配置推理选项。在使用Paddle Inference推理部署过程中,我们通过AnalysisConfig对配置推理的相关参数,包括不限于对设备的配置(CPU/GPU),模型路径的设置,是否开启图优化,内存/显存优化等。

2)创建AnalysisPredictor。根据设定好的AnalysisConfig创建推理引擎predictor,创建期间会进行模型加载,分析优化等工作。

3)准备输入数据。获取模型的所有输入tensor,并将数据设置到tensor中。

4)运行推理。

5)获取模型输出。拿到模型的所有输出tensor,并获取tensor中的数值。

下面通过一段简单的程序介绍如何使用Paddle Inference Python API进行模型推理。具体的代码如下:

代码语言:javascript复制
# -*- coding: UTF-8 -*-
# 导入PaddleInference、Numpy相关类库
import numpy as np
from paddle.fluid.core import AnalysisConfig
from paddle.fluid.core import create_paddle_predictor

class Model:
   def __init__(self, model_file, params_file, use_mkldnn=True, use_gpu = False, device_id = 0):
     # 1)通过AnalysisConfig API配置推理引擎
     config = AnalysisConfig(model_file, params_file)
     # 使用ZeroCopy 模式,运行期间关闭feed fetch op
     config.switch_use_feed_fetch_ops(False)
     # 打开显存优化 
     config.enable_memory_optim() 
     if use_gpu:
       print ("ENABLE_GPU")
       # 设置使用GPU
# 400表示预先分配显存大小,device_id表示使用哪一个GPU
       config.enable_use_gpu(400, device_id)
     # 2)创建predictor
     self.predictor = create_paddle_predictor(config)

   def run(self, img_list):
     # 3) 准备输入
     input_names = self.predictor.get_input_names() 
     for i, name in enumerate(input_names):  # 对每个输入进行设置
       input_tensor = self.predictor.get_input_tensor(input_names[i])
       input_tensor.reshape(img_list[i].shape) 
       # 将数据copy到tensor中  
       input_tensor.copy_from_cpu(img_list[i].copy())

     # 4) 执行推理
     self.predictor.zero_copy_run()

     results = []
     output_names = self.predictor.get_output_names()
     # 5) 获取所有的输出并放入results中
     for i, name in enumerate(output_names):
       output_tensor = self.predictor.get_output_tensor(output_names[i])
       output_data = output_tensor.copy_to_cpu()
       results.append(output_data)
     return results

以上代码展示了如何使用Paddle Inference 进行推理,代码中构建了一个Model类,其中__init__(model_file, model_params) 构造函数会根据传入的模型路径,以及use_mkldnn, use_gpu参数创建AnalysisPredictor。类中的run()函数接收数据并进行推理,并返回模型输出。

因此我们可以通过以下两行代码来进行模型加载以及模型推理:

代码语言:javascript复制
model = Model("./model", "./param") # 构建predictor
result = model.run([img])  # 模型推理,返回推理结果

在下文口罩检测任务中,我们都将基于此Model类进行模型构建以及模型推理。

2. 基于预测类进行人脸检测模型部署

在整个口罩检测流任务中,首先做的一件事是对图像中的人脸进行检测。在这一节,我们用Paddle Inference Python API来构建人脸检测模型。

1) 我们使用第2部分中讲述的Model类构建人脸检测对象,其中__model__文件表示人脸检测模型的结构文件,__params__表示模型的参数文件。

代码语言:javascript复制
face_detector = Model('./pyramidbox_lite/__model__', './pyramidbox_lite/__param__')

2) 人脸检测图像预处理

代码语言:javascript复制
import cv2
import numpy as np
from PIL import Image
import math

def face_detect_preprocess(img, shrink):
   img_shape = img.shape
   # 根据shrink缩放图片
# 图片缩放后的高度在300-500间,保证模型精度同时,也能加快推理速度。
   img = cv2.resize(img, (int(img_shape[1] * shrink), int(img_shape[0] * shrink)), interpolation=cv2.INTER_CUBIC)
   # 将HWC格式转化为CHW格式 
   img = np.swapaxes(img, 1, 2)
   img = np.swapaxes(img, 1, 0)

   # 均值以及方差是通过对训练所有图片统计得到的。
   mean = [104., 117., 123.]
   scale = 0.007843
   img = img.astype('float32')
   # 减去图片的均值,乘以方差倒数。
   img -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
   img = img * scale
   img = img[np.newaxis, :]
   return img

3) 读取图片并进行人脸检测模型推理。

下载人脸图片:

代码语言:javascript复制
wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/nano_mask_detection/test_mask_detection.jpg
代码语言:javascript复制
# 读取图片
ori_img = cv2.imread('test_mask_detection.jpg')
print (ori_img.shape) #  该图片为高1050(y轴), 长1682(x轴)的图片
# (1050, 1682, 3)
img_h, img_w, c = img.shape
# 人脸检测图像预处理
# 0.3表示将读取的图片长,宽的大小缩小至原来的0.3倍
img = face_detect_preprocess(ori_img, 0.3) 
# 使用Model类中的run函数,运行人脸检测, result为模型运行的结果
result = face_detector.run([img])

print (result[0])
# [[1.         0.99998796 0.27059144 0.18095288 0.39210612 0.43089798]
# [1.         0.99998593 0.5600477  0.32936218 0.66750807 0.55742574]
# [1.         0.9999182  0.693954   0.28346226 0.7878771  0.47385922]
# [1.         0.01414413 0.89871734 0.6311271  0.96674687 0.9164002 ]]

可以看到,该模型的输出结果共有四行,每一行的第二个数字代表人脸的置信度,后四个数字表示人脸区域左上角以及右下角的位置信息。

我们拿输出结果的第一行来详细说明下每个数字的含义:

第一行结果

[1. 0.99998796 0.27059144 0.18095288 0.39210612 0.43089798]

0.99998796 表示该区域是人脸的置信度。

0.27059144 表示该区域在原图中左上角的x轴信息,x轴的坐标可以通过 (0.27059144 * 1682) 得到。

0.18095288 表示该区域在原图中左上角的y轴信息,y轴的坐标可以通过 (0.18095288 * 1050) 得到。右下角的信息也可以通过类似上述方式求得。

4) 获取人脸的坐标信息

通过上一节我们知道,模型输出的坐标信息是一个小数,我们通过以下代码来获取人脸在原图中坐标的真实值。

代码语言:javascript复制
# 该函数将检测模型的输出,原图的高度以及长度信息作为输入
# 输出所有人脸的左上角坐标以及人脸区域的高度,长度信息。
def get_faces(data, h, w):
  faces_loc = []
  for d in data:
    if d[1] >= 0.5:
      x_min = max(d[2] * w, 0)
      y_min = max(d[3] * h, 0)
      x_h = min((d[4] - d[2]) * w, w)
      y_w = min((d[5] - d[3]) * h, h)
      faces_loc.append([int(x_min), int(y_min), int(x_h), int(y_w)])
  return faces_loc

faces = get_faces(result[0], img_h, img_w)
print (faces) 
# [[455, 190, 204, 262], [942, 345, 180, 239], [1167, 297, 157, 199]] 

3.3 基于预测类进行口罩分类模型的部署

1) 我们使用第2部分中讲述的Model类构构建口罩分类的Model对象。

mask_classify = Model('./mask_detector/model', './mask_detector/params')

2) 口罩分类模型图像预处理

在进行口罩分类模型推理前,我们需要对人脸的图片进行预处理。

代码语言:javascript复制
import cv2
import numpy as np
from PIL import Image
import math

# img 为原始图片
# pts为单个人脸的坐标信息,包含人脸左上角,右上角,左下角,右下角在原始图片中的坐标信息。
def mask_classify_preprocess(img, pts):
   img_face, _ = crop(img, pts)
   t_img_face = img_face.copy()
   img_face = img_face / 256.
   # 将HWC格式转化为CHW格式 
   img_face = np.swapaxes(img_face, 1, 2)
   img_face = np.swapaxes(img_face, 1, 0)

   # 均值是通过对训练中所有人脸的图片统计得到的。
   mean = [0.5, 0.5, 0.5]
   img_face = img_face.astype('float32')
   # 减去图片的均值。
   img_face -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
   img_face = img_face.reshape(-1, 3, 128, 128) 
   return img_face, t_img_face

3)口罩分类

在人脸检测章节中进行了人脸检测,通过模型输出结果了解到,模型检测到了三张人脸,通过get_faces 函数获取到了人脸的真实坐标信息并保存在faces变量中。在这一部分中,将使用口罩分类模型,对这些人脸是否戴口罩进行分析判断。

代码语言:javascript复制
faces_with_mask_conf = []
# 遍历所有的人脸
for loc in faces:
   pts = np.array([loc[0], loc[1], loc[2]   loc[0], loc[1], loc[0], loc[1]   
    loc[3], loc[2]   loc[0], loc[1]   loc[3]]).reshape(4, 2).astype(np.float32)

   # 人脸图片预处理
   face_img_t, temp_face = mask_classify_preprocess(ori_img, pts)
   # 使用Model类中的run函数,运行口罩分类模型
   mask_results = mask_classify.run([face_img_t])
   # 获取戴口罩的置信度
   mask_conf = mask_results[0][0][1] 
   temp_loc = loc
   temp_loc.append(mask_conf) 
   faces_with_mask_conf.append(temp_loc)

# 结果显示
print (faces_with_mask_conf)
# [[455, 190, 204, 262, 0.993429], 
#    [942, 345, 180, 239, 0.9189134], 
#     [1167, 297, 157, 199, 0.28184703]]

我们遍历每一张人脸的坐标,根据坐标将人脸从从原图中截取出来,经过图像预处理后通过口罩分类模型获取到该人脸是否带有口罩的置信度(置信度的值越大说明戴口罩的概率越大)。

04

结果可视化

到这一步,我们已经完成了对图片中的人脸进行检测,并对每个人脸进行是否戴有口罩的判断,接下来我们通过以下代码将检测的结果进行可视化展示。

代码语言:javascript复制
from PIL import Image
from PIL import ImageDraw, ImageFont

# 传入原始图片,人脸的坐标位置以及戴有口罩置信度信息, 
# 该函数会将戴口罩人脸画上蓝框,不戴口罩的人脸画上红框。
def draw_boxes(img, boxes):
   h, w, _ = img.shape
   image = Image.fromarray(img)
   draw = ImageDraw.Draw(image)
   for box in boxes:
     x_min = box[0] 
     y_min = box[1] 
     x_max = box[0]   box[2]
     y_max = box[1]   box[3]
     (left, right, top, bottom) = (x_min, x_max, y_min, y_max)
     color = "red"
     if box[4] < 0.6:
        color = "blue"
     draw.line(
          [(left - 10, top - 10), (left - 10, bottom   10), 
            (right   10, bottom   10), (right   10, top - 10),
           (left - 10, top - 10)],
          width=10,
          fill=color)
     conf_text = str(box[4])
   img = np.asarray(image)
   return img
drawed_img = draw_boxes(ori_img, faces_with_mask_conf)
cv2.imshow("mask_faces", drawed_img)
cv2.waitKey(0)

运行上述程序会在桌面上弹出带有画框的图片。

总结

本文介绍了如何使用Paddle Inference Python API进行模型部署,并对代码进行了详细的解释,接着一步一步讲解如何使用Paddle Inference在服务器上进行口罩模型部署。除此之外,我们还提供了整套代码,下载链接:

https://github.com/PaddlePaddle/Paddle-Inference-Demo/tree/master/python/mask_detection

代码下载后解压运行cam_video.py, 程序会从摄像头读取图像,然后实时进行口罩检测。

说到底,本文讲述的口罩检测只是单纯的功能而已,发挥想象力,也许你能创造出更多有意思的应用!讲到这里,有没有感觉部署模型也挺简单呢,那还等什么,赶紧在自己的机器上测试下吧!

如果您加入官方QQ群,您将遇上大批志同道合的深度学习同学。官方QQ群:703252161。

如果您想详细了解更多飞桨的相关内容,请参阅以下文档。

官网地址:

https://www.paddlepaddle.org.cn

飞桨开源框架项目地址:

GitHub:

https://github.com/PaddlePaddle/Paddle

Gitee:

https://gitee.com/paddlepaddle/Paddle

END

深度学习开发者峰会报名

由深度学习技术及应用国家工程实验室与百度联合主办的“WAVE SUMMIT”2020深度学习开发者峰会将于5月20日召开,并首次采用线上直播的方式举办,本次峰会飞桨将发布核心框架的重要升级,并有多项新品发布及重磅升级,还等什么,快上官网注册吧:

https://www.wavesummit.com.cn/

前5000名注册用户将有机会获得大奖哦!

0 人点赞