【深度学习】搭建人工智能服务网站(安全帽检测)

电力图像分类最典型的场景就是安全帽佩戴识别。

针对电网作业现场人员行为的图像数据,采用目标检测、图像识别等人工智能技术,对电网作业现场人员是否规范佩戴安全帽进行检测识别。通过计算平均精确率、漏检率、误检率、平均计算时间等指标进行评测。

任务拆解

  1. 输入是图像数据,没有文本、语音等其它数据。

  2. 可将问题拆解为图像识别、目标检测、图像分类等任务。

  3. 具体是谁没有佩戴安全帽就需要用到人脸识别。

  4. 安全帽有佩戴要求和规则,我们需要去标注数据来匹配这个规则:帽子带在头上;帽子固定扣是否扣住。

  5. 对帽子带着头上数据标注的时候,同时标注帽子在头上带的作为正样本,还要标注只有帽子、只有脑袋的负样本,正负样本最好还是在电网作业现场这种场景下。

  6. 我们没有那么多不规范的数据,也没有那么多时间去标注数据。所以本文 问题简化为识别是否佩戴,问题转换为一个图像的二分类问题。

深度学习框架

深度学习框架:tensorflow(比较重)/pytorch(其次)/paddlepaddle(最好用)

很多人工智能开源的项目tensorflow(比较重)/pytorch(其次)这两种实现,也有paddle的实现,如果没有,我们可以参考这个paddle的规范把pytorch代码迁移过来,工作量不大。

常规安全帽检测流程

一. 准备数据

  1. 准备数据要注意场景匹配;如果标注数据的场景和实际使用的场景不一样的话,会有新的干扰因素影响你的准确率。

  2. 正负样本数据量要注意平衡的问题,如果正样本标注1万,负样本标注20万,让人工智能去分类,人工智能就会偷懒,我全部都识别为没有带安全帽就好了。

  3. 单纯的图像采样效果有限,我们最好做多种类型的数据增强。常见的数据增强mixup、cutmix,都是很规则的矩形边界。snapmix这个可以实现非矩形图像的切割填补等处理,对提升准确率有很大帮助。

  4. 数据需要做预处理:数据格式转换(目录结构、标签文件)、图片大小统一。

  5. 数据标注的数据质量问题可由数据标注质检人员完成,但成本高,cleanlab可以实现错误标签自动筛选。

二. 数据标注

  1.  要做目标检测,把我们要找的东西在图片上面自动框出来,才需要做框图标注,如果只是单纯的做图片分类,是不用画框标注的,比如,对鸟类做分类的话,但是把各类图片分门别类放到目录上去,也算是数据标注。

  2. 数据标注,准确率要求不一样,可能标注的方法也不一样,常见的我们就拉四边形的框,但是有的时候,我们可能要多边形。

  3. voc是一种数据规范的格式,这个规范的格式一般来说,包含目录结构、标签文件的格式要求。

三. 选择模型

  1. 常规是目标检测+图像分类,图像二分类能选的模型比较多,重点考虑:准确率、处理速度、模型大小(主要考虑将来产品化了,这个模型的运行环境),作为练习来说,我们基本上考虑准确率、召回率就可以了。

  2. 往往会选择多个模型去比较,并且做模型融合。

四. 训练模型

  1. 训练前,做shuffle洗牌对图片数据做打乱处理。

  2. 图片数据按照训练集、验证集、测试集划分,8:1:1。

  3. 开始训练,不断改进,提升效率,调参,是人工智能训练师、调参侠表演的时刻了,调参也可以用工具自动搜索最好参数:自动调参工具NNI。

  4. 还有一点特别重要的,如果你不是专业学人工智能CV,你不要花太多时间去研究模型的改进,你就选择市面上效果最好的模型就可以了。(这里我暗讽一下浙江大学孟伟,他的课题就是模型改进,发不出论文,菜是原罪)

五. 模型评估

通过计算平均精确率、漏检率、误检率、平均计算时间等指标进行评测。

进阶学习

如果大家需要进阶研究学习,可以多去研究学习kaggle、天池上面的相关的竞赛,这上面经常会有很多创新的模型、算法。

kaggle:全球最顶级的人工智能竞赛平台。https://www.kaggle.com/

天池:阿里提供国内最顶级的人工智能竞赛平台。

本次开发任务

  1. 找到训练好的安全帽检测预测模型,在本地运行起来。

  2. 把这个模型封装成可调用的类。

  3. 用flask搭建网站来调用我们封装好的类实现在线安全帽检测预测业务。

flask网站

  1.  轻量级的web框架,本身采用jinja2模板,这个模板的作用是可以将我们的html代码和数据融合到一起。

  2. @app.route('/xxx')做路径映射(这个映射的就是/xxx这个路径和一个对应函数的映射),我们正常是访问到127.0.0.1:5000/  (这个斜杠代表根目录),所以写路径的时候,一定是/开头的,然后这个@app.route会自动绑定到它最近的这个函数上,所以@app.route里面路径和函数名不一定要完全一致,但是我们一般写成一致,是出于命名规范。函数就是我们常见的函数,是完全一样的。

  3. flask 接受前端参数的几种方式:

    # GET,url参数

    path = request.args.get("imgPath")

    path1 = request.values.get("imgPath")

    # POST,数据包参数

    path2 = request.form.get("imgPath2")

    path3 = "dd" # request.get_data().get("imgPath2")
    path4 = request.get_json()

    path5 = request.get_data()

# header,header参数

path6 = request.headers["Content-Type"]

api封装

  1.  简单粗暴的方法,就是用subprocess直接模拟命令行调用的方式,这种方式好处是简单,干净利落,不用import,所有的麻烦事都交给命令行环境去处理。

  2. 引入包的方式,这种方式比较精准,也不算麻烦,但是得看你用的东西的作者是否给你足够的示例代码。

  3. 直接把项目的源代码整合到我们的flask项目里面,作为其中的模块来使用,这个比较麻烦,会引发一些包路径的问题。

代码实现

https://github.com/PaddlePaddle/PaddleClas/blob/release/2.5/docs/zh_CN/models/PULC/PULC_safety_helmet.md

该案例提供了用户使用 PaddleClas 的超轻量图像分类方案(PULC,Practical Ultra Lightweight image Classification)快速构建轻量级、高精度、可落地的“是否佩戴安全帽”的二分类模型。该模型可以广泛应用于如建筑施工场景、工厂车间场景、交通场景等。

#安装 paddlepaddle
pip install paddlepaddle
#安装 paddleclas
pip install paddleclas

如果安装失败就下载源代码,进入代码目录,执行:python setup.py install进行离线安装。

下载样本来测试:

https://paddleclas.bj.bcebos.com/data/PULC/pulc_demo_imgs.zip

safety_helmet_test_1.png

ae0c0a073f1455dcc6f23faa90f72aab.png

safety_helmet_test_2.png

76fa81bcc313d95e0668a2e30a624d29.png

paddleclas --model_name=safety_helmet --infer_imgs=pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png
[2022/10/18 21:26:47] ppcls INFO: class_ids: [1], scores: [0.9986255], label_names: ['unwearing_helmet'], filename: pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png
[2022/10/18 21:26:47] ppcls INFO: Predict complete!

safety_helmet_test_1.png预测出的标签是:unwearing_helmet。

paddleclas --model_name=safety_helmet --infer_imgs=pulc_demo_imgs/safety_helmet/safety_helmet_test_2.png
[2022/10/18 21:27:41] ppcls INFO: class_ids: [0], scores: [0.9977983916178346], label_names: ['wearing_helmet'], filename: pulc_demo_imgs/safety_helmet/safety_helmet_test_2.png
[2022/10/18 21:27:41] ppcls INFO: Predict complete!

safety_helmet_test_2.png预测出的标签是:wearing_helmet。

我们已经可以利用cmd命令来实现预测,下面我们用python代码来实现预测:

import paddleclas
model = paddleclas.PaddleClas(model_name="safety_helmet")
result = model.predict(input_data="pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png")
print(next(result))
[{'class_ids': [1], 'scores': [0.9986255], 'label_names': ['unwearing_helmet'], 'filename': 'pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png'}]

完美,在MyPredict.py中把预测能力封装成类:

# encoding=utf-8
import os
import subprocess
import paddleclas


class CMD(object):
    def __init__(self):
        pass


    # 直接调用系统cmd命令行去执行。
    def doPredict1(self, imgPath):
        cmd = "paddleclas --model_name=safety_helmet --infer_imgs="+imgPath
        os.system(cmd)


    # subprocess 模块允许我们启动一个新进程,并连接到它们的输入/输出/错误管道,从而获取返回值。
    def doPredict2(self,imgPath):
        cmd = "paddleclas --model_name=safety_helmet --infer_imgs="+imgPath
        p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,stderr=subprocess.STDOUT,encoding='utf-8')  # 将标准输出重定向到当前子进程
        p1 = subprocess.Popen("", shell=True, stdout=None, stderr=None, encoding='utf-8')  # 将标准输出还原到ide下的输出
        content = p.communicate()[0]
        print(content)  # 正常的一个print,要把内容输出到当前窗口
        return content


class FUN(object):
    def doPredict3(self,imgPath):
        model = paddleclas.PaddleClas(model_name="safety_helmet")
        result = model.predict(input_data=imgPath)
        res = next(result)
        print(res)
        return str(res)


# 实现三种方式的预测
if __name__ == "__main__":


    cmd = CMD()
    cmd.doPredict1("pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png")


    cmd = CMD()
    cmd.doPredict2("pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png")


    fun = FUN()
    fun.doPredict3("pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png")

运行MyPredict.py可验证三种方式均可正常预测:

[2022/10/18 22:24:05] ppcls WARNING: The current running environment does not support the use of GPU. CPU has been used instead.
e[37m---    Fused 0 subgraphs into layer_norm op.e[0m
[2022/10/18 22:24:05] ppcls INFO: class_ids: [1], scores: [0.9986255], label_names: ['unwearing_helmet'], filename: pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png
[2022/10/18 22:24:05] ppcls INFO: Predict complete!


[2022/10/18 22:24:13] ppcls WARNING: The current running environment does not support the use of GPU. CPU has been used instead.
e[37m---    Fused 0 subgraphs into layer_norm op.e[0m
[2022/10/18 22:24:13] ppcls INFO: class_ids: [1], scores: [0.9986255], label_names: ['unwearing_helmet'], filename: pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png
[2022/10/18 22:24:13] ppcls INFO: Predict complete!


[2022/10/18 22:24:13] ppcls WARNING: The current running environment does not support the use of GPU. CPU has been used instead.
e[37m---    Fused 0 subgraphs into layer_norm op.e[0m
[{'class_ids': [1], 'scores': [0.9986255], 'label_names': ['unwearing_helmet'], 'filename': 'pulc_demo_imgs/safety_helmet/safety_helmet_test_1.png'}]

把MyPredict.py放入文件夹core,只需要import设计好的类就可以获得安全帽预测能力。

from core.MyPredict import CMD, FUN

新建一个flask工程,整个工程布局如下:

a1b53e9aba156c8d8cb98d2494663591.png

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
{{ msg }}
</body>
</html>

app.py完成flask网站编写:

# encoding=utf-8


from flask import Flask
from flask import request
import json


from core.MyPredict import CMD, FUN
from flask import render_template


# flask 是python非常轻量级的一个web框架
# 在线的版本,这个代码运行在服务器端,浏览器端、客户端来访问,这个就相当于百度开放的api


# 创建应用实例
app = Flask(__name__)


# Flask中的route()装饰器用于将URL绑定到函数
# 设置主页显示
@app.route('/', methods=["GET", "POST"])
def index():
    return render_template("index.html", msg="你好,这是安全帽预测服务网站")


# 处理字符串的函数,提取需要的部分
def extractContent(res):
    return res.split("\n")[-3]


@app.route('/predict1', methods=["GET", "POST"])  # 这个注解作用,就是做了一个路径映射,默认只支持GET方法,如果要POST,必须加上
def predict1():
    #  获得前端传来的参数
    # GET,url参数
    path = request.args.get("imgPath")
    path1 = request.values.get("imgPath")
    # POST,数据包参数
    # path2 = request.form.get("imgPath2")
    # path3 = "dd"  # request.get_data().get("imgPath2")
    # path4 = request.get_json()
    # path5 = request.get_data()
    # header,header参数
    # path6 = request.headers["Content-Type"]


    print(path1)
    # print(path2)
    # print(path3)
    # print(path4)
    # print(path5)
    # print(path6)
    # img = request.args.get("imgBase64")
    cmd = CMD()
    res = cmd.doPredict2(path)
    res = extractContent(res)
    return json.dumps({"status":"ok","result":res})


# 路径必须/开头
@app.route('/v1/predict2')
def predict2_v1():
    cmd = CMD()
    path = request.args.get("imgPath")
    res = cmd.doPredict1(path)
    return json.dumps(res)


@app.route('/v2/predict2')
def predict2_v2():
    cmd = CMD()
    path = request.args.get("imgPath")
    res = cmd.doPredict2(path)
    return json.dumps(res)


@app.route('/predict3')
def predict3():
    fun = FUN()
    path = request.args.get("imgPath")
    res = fun.doPredict3(path)
    return json.dumps(res)


# 启动服务
if __name__ == '__main__':
    app.run()

运行app.py:

49129a1057dcaf63d75627a771db7d49.png

打开网页:http://127.0.0.1:5000/

f957c20aa359de259253d641cbfa7904.png

测试/predict1:

a076695b5ee6a62ae5a3b0738f08b95c.png

测试/v1/predict2:

3b2601fbfbcd3f5b8f828b54c8d577cf.png

返回null是因为doPredict1函数没有返回任何值。

# 直接调用系统cmd命令行去执行。
    def doPredict1(self, imgPath):
        cmd = "paddleclas --model_name=safety_helmet --infer_imgs="+imgPath
        os.system(cmd)

测试/v2/predict2:

ae5b1098b43a2331e559406bed922e34.png

测试/predict3:

720a980f68daa344cd37ec26c9fa87c2.png

至此我们完成了具有安全帽检测预测服务的简单网站搭建,基本功能已经完成,剩下的任务就是做合适的前端设计,让用户方便使用。

 
 

d26d4b115c023bb982d3133a3e3be86c.jpeg

 
 
 
 
 
 
 
 
往期精彩回顾




适合初学者入门人工智能的路线及资料下载(图文+视频)机器学习入门系列下载机器学习及深度学习笔记等资料打印《统计学习方法》的代码复现专辑机器学习交流qq群955171419,加入微信群请扫码
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值