专注app软件定制开发【目标检测】Flask+Docker在服务器部署YOLOv5应用

前言

专注app软件定制开发看到不少文章讲解用部署YOLOv5的,专注app软件定制开发不过基本都在本地上能专注app软件定制开发够运行而戛然而止。因此,专注app软件定制开发我打算再进一步,利用Docker专注app软件定制开发在云服务器上部署YOLOv5,专注app软件定制开发这样就能够开放给别人使用。

代码仓库:

本地部署

专注app软件定制开发本地项目主要参考了robmarkcole专注app软件定制开发的这个项目[1],专注app软件定制开发原始项目是一年前多发专注app软件定制开发布的大概用的是较早的版本,直接download专注app软件定制开发下来会出现一些问题。于是我使用YOLOv5-5.0版本进行了重构。

项目结构

整体项目结构如下图所示:

  • models:存放模型构建相关程序,直接从yolov5-5.0版本中clone过来
  • utils:存放绘图、数据加载等相关工具,直接从yolov5-5.0版本中clone过来
  • static:存放前端渲染等静态文件
  • templates:前端页面html文件
  • webapp.py:入口程序

整体看来,整个项目作为一个demo还是比较简单的。当然utils和models里面存在一定的冗余,有的工具类是为训练测试提供服务,这里仅需要做推理即可。本来想着再进一步精简,不过发现各函数之间相关性挺大,遂不去修改。

快速运行

仓库里已经存放了yolov5s.pt文件,无需额外下载模型文件。
在终端运行python webapp.py,稍等片刻,即可访问 http://127.0.0.1:5000


在首页中选择文件再上传,即可返回出模型预测结果。预测后的图片会保存在static文件夹下。

代码简析

核心代码:

@app.route("/", methods=["GET", "POST"])def predict():    if request.method == "POST":        if "file" not in request.files:            return redirect(request.url)        file = request.files["file"]        if not file:            return        img_bytes = file.read()        img = Image.open(io.BytesIO(img_bytes))        img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)        if img is not None:            showimg = img            with torch.no_grad():                img = letterbox(img, new_shape=imgsz)[0]                # Convert                # BGR to RGB, to 3x416x416                img = img[:, :, ::-1].transpose(2, 0, 1)                img = np.ascontiguousarray(img)                img = torch.from_numpy(img).to(device)                img = img.half() if model.half() else img.float()  # uint8 to fp16/32                img /= 255.0  # 0 - 255 to 0.0 - 1.0                if img.ndimension() == 3:                    img = img.unsqueeze(0)                # Inference                pred = model(img)[0]                # Apply NMS                pred = non_max_suppression(pred, conf_thres, iou_thres)                # Process detections                for i, det in enumerate(pred):  # detections per image                    if det is not None and len(det):                        # Rescale boxes from img_size to im0 size                        det[:, :4] = scale_coords(                            img.shape[2:], det[:, :4], showimg.shape).round()                        # Write results                        for *xyxy, conf, cls in reversed(det):                            label = '%s %.2f' % (names[int(cls)], conf)                            plot_one_box(                                xyxy, showimg, label=label, color=colors[int(cls)], line_thickness=2)        imgFile = "static/img.jpg"        cv2.imwrite(imgFile, showimg)        return redirect(imgFile)    return render_template("index.html")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

前端通过POST的方式,将图片提交到后端,首先需要判断图片是否为空,如果为空,则返回空值,即报错界面;如果不是空值,则通过file.read()来读取图片字节串,原代码是通过PIL.Image来转成图片,为了和后面的推理过程兼容,转换成OpenCV格式。
推理部分代码基本完全copy自YOLOv5的detect.py,推理之后的图片首先进行保存,然后再返回给前端进行直接显示。

云端部署

在服务器部署也有多种方案,最容易想到的就是直接在服务器搭建python环境,不过考虑到还需要安装torch这种大型库,出错概率高,因此更方便的就是使用进行部署。

简单理解,Docker就像是一个自带了虚拟环境和程序的容器,只需要将其打包放在服务器,直接就可以运行。

生成requirements.txt

第一步是需要生成依赖文件列表requirements.txt,以便在Docker Image中能够配置好需要的依赖。
通常的做法是这样进行生成:

pip freeze > requirements.txt
  • 1

然后就可以在新环境中,这样快速安装:

pip install -r requirements.txt
  • 1

但是这样做的一个巨大问题是,它会将环境中所有的库名称和版本进行输出,有些库是在项目中没有用到的,但依然会进行输出。

为了避免这种情况,有人就开发了一个pipreqs库,它可以进行一些过滤,仅将工程中用到的库和版本进行输出。

pipreqs的安装可以有两种方式:
方式一:

pip install pipreqs
  • 1

方式二:
如果pip失败,可以去Github上克隆该项目,然后运行setup.py

git clone https://github.com/bndr/pipreqs.gitpython setup.py install
  • 1
  • 2

安装好之后,再在当前目录下运行

pipreqs . --encoding=utf8 --force
  • 1

这样就能生成requirement.txt

coremltools==5.2.0Flask==2.2.2matplotlib==3.5.2numpy==1.21.5onnx==1.12.0pafy==0.5.5pandas==1.3.5Pillow==9.2.0PyYAML==6.0requests==2.28.1scipy==1.7.3seaborn==0.11.2setuptools==63.2.0torch==1.11.0torchvision==0.12.0tqdm==4.64.0opencv-python==4.6.0.66
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意生成之后需要检查一下,比如云服务器不具有GPU环境,那么就手动将torch改成CPU版本。

构建DockerFile

DockerFile是构建文件,包含了所有环境配置步骤,比如安装库。

常用指令有这些[2]:

FROM             # 基础镜像,一切从这里开始构建  centosMAINTAINER        # 镜像是谁写的, 姓名+邮箱RUN             # 镜像构建的时候需要运行的命令ADD             # 步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录WORKDIR         # 镜像的工作目录VOLUME             # 挂载的目录EXPOSE             # 暴露端口配置  和我们的-p一样的CMD             # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。ENTRYPOINT         # 指定这个容器启动的时候要运行的命令,可以追加命令ONBUILD         # 当构建一个被继承 DockerFile 这个时候就会运行ONBUILD的指令,触发指令。COPY             # 类似ADD,将我们文件拷贝到镜像中ENV             # 构建的时候设置环境变量
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

构建的DockerFile内容如下:

FROM python:3.7-slim-busterRUN apt-get updateRUN apt-get install ffmpeg libsm6 libxext6  -yWORKDIR /appADD . /appRUN pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple/EXPOSE 5000CMD ["python", "webapp.py"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

首先,从python:3.7-slim-buster这个公开镜像中,引入python环境,然后更新数据源,安装三个必要的工具。

之后,指定工作路径在/app这个文件夹下,这个路径设置很重要,后面会用到。

然后就安装requirements.txt里面所列的所有依赖,注意这里使用了阿里源,这样可以进行加速。

接着暴露出5000这个端口,因为后面要通过这个端口号进行访问。

最后CMD指定容器运行之后就执行的命令,即容器一旦运行就执行python webapp.py,将程序跑起来。

Docker打包上传

在注册之前,需要在本地安装Docker并进行注册,Windows系统可以安装Docekr的客户端,这里不做赘述。

打开客户端之后,就能在本地启动Docker服务,然后进入到项目终端,输入

docker build --tag zstar1003/yolov5-flask .
  • 1

注意最后面有个点,这代表着将所有内容打包成镜像。--tag指定了镜像名称,注意前面必须是用户名,否则后面将不能够进行拉取。如果前面tag忘记添加用户名,可以在打包之后进行更名,使用docker tag 原始名 zstar1003/yolov5-flask

关于Docker的命名规则,可以看[3],讲解得较为详细。

打包过程比较漫长,因为系统需要去联网下载前面那些依赖,打包完成之后,在终端输入docker images可以看到本地的所有镜像。

本地有了镜像之后,再将其push到公开仓库,这样方便后续拉取,执行命令:

docker push zstar1003/yolov5-flask
  • 1

上传的过程也比较长,主要取决于镜像的大小和网速,上传完之后,可以在客户端的这个位置看到。

Docker镜像拉取

下面就是在云服务器上进行操作了,推荐使用FinalShell连接云服务器。

首先需要在云服务器上安装Docker,我是用的云服务器系统是Centos 7.6。
先装一些必要的软件包

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
  • 1

设置稳定的仓库

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
  • 1

安装社区版的Docker

sudo yum install docker-ce docker-ce-cli containerd.io
  • 1

安装好之后,启动Docker

systemctl start docker
  • 1

然后就可以拉取之前上传的镜像

docker pull zstar1003/yolov5-flask
  • 1

拉取好之后,输入docker image -a看看镜像是否存在,存在就说明拉取成功。

Docker创建容器并启动

拉取完镜像之后,就需要创建一个容器来挂载镜像,主要命令是docker run,有下列这些可选参数,更多命令可参考[4]

docker run [Options] image#参数说明--name="名字"           指定容器名字-d                     后台方式运行-it                    使用交互方式运行,进入容器查看内容-p                     指定容器的端口	-p ip:主机端口:容器端口  配置主机端口映射到容器端口	-p 主机端口:容器端口(常用)	-p 容器端口-P                     随机指定端口-e					   环境设置-v					   容器数据卷挂载
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

于是输入docker run -p 5000:5000 zstar1003/yolov5-flask来创建一个容器来运行这个镜像,结果报错,原因是5000端口被占用。这是因为我这台服务器上之前跑过别的项目,5000端口有其它的进程在工作。

遇到这情况,可以用lsof来查询冲突的端口存在哪个进程。

首先安装lsof

yum -y install lsof
  • 1

然后输入

lsof -i :5000
  • 1

如下图所示,可以看到5000端口被gunicorn这个进程正在使用,于是将其kill掉。

杀完之后,再重启容器,首先输入docker ps -a,查看刚刚创建的容器ID


可以看到它的ID是34960ff95951,然后将其启动

docker start 34960ff95951
  • 1

启动之后,看到终端输入下列内容,表示程序正常运行。

这时候访问服务器公网IP:5000端口,可以看到前端界面已经显示出来。

错误排除

然而,当我上传图片,点击按钮时,突然报错:

RuntimeError: “slow_conv2d_cpu” not implemented for ‘Half’

我在Github的issue[5]中找到了这个问题的答案,原回答如下:

Q: Error “slow_conv2d_cpu” not implemented for ‘Half’
A: In order to save GPU memory consumption and speed up inference, Real-ESRGAN uses half precision (fp16) during inference by default. However, some operators for half inference are not implemented in CPU mode. You need to add --fp32 option for the commands. For example, python inference_realesrgan.py -n RealESRGAN_x4plus.pth -i inputs --fp32

翻译一下,就是本机上为了加速推理,使用了model.half()半精度(fp16)进行转换,然后,这只能在GPU版本的Pytorch中使用,在CPU版本的Pytorch中会报错。

于是,就得想办法把docker中的文件进行修改,将half的操作进行移除。

还记得之前DockerFile中指定的路径吗?在之前,指定了Docker工作路径在app文件夹下,因此,可以使用下面的命令,将其拷贝出来。

docker cp 34960ff95951:/app/webapp.py /home/torch/
  • 1


如下图所示,在两个half()的地方进行修改,图片直接使用float()类型。


修改之后,再把文件拷贝回去,这样会覆盖原文件,达到修改的目的。

docker cp  /home/torch/webapp.py 34960ff95951:/app/
  • 1

修改好之后,重启容器:

docker restart 34960ff95951
  • 1

然而在此运行时,我又遇到了下面这个报错

AttributeError: ‘Upsample’ object has no attribute ‘recompute_scale_factor’


查阅相关资料,这个时pytorch版本的一个Bug,upsampling.py文件中,存在了recompute_scale_factor参数冗余。

和上面操作类似,把该文件拷贝出来,进行修改,再拷贝回去即可。注意该文件属于依赖文件,拷贝出来需要先修改文件的读写权限。

运行效果

排除完这两个错误之后,再次重启容器,上传图片,可以看到推理结果已经正确得呈现出来!

总结

本次利用Docker部署遇到许多阻碍。下次部署时,如果服务器是CPU环境,最好先在本地利用CPU运行一下,如果跑通再进行镜像打包。

References

[1]https://github.com/robmarkcole/yolov5-flask
[2]https://liuhuanhuan.blog.csdn.net/article/details/123256877
[3]https://www.zsythink.net/archives/4302
[4]https://blog.csdn.net/weixin_45698637/article/details/124213429
[5]https://github.com/xinntao/Real-ESRGAN/blob/master/docs/FAQ.md

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发