一、前言
记录时间 [2024-4-15]
系列文章简摘:
Docker 学习笔记(二):在 Linux 中部署 Docker(Centos7 下安装 docker、环境配置,以及镜像简单使用)
API 接口简单使用(二):Python 中使用 Flask(接口封装整理版,含文件上传接口的详细实现)
YOLOv8 测试 5:Linux 中 Docker 部署 YOLOv8,Python 封装 API 接口,base64 图片处理
更多 YOLOv8 测试相关文章请参考上面专栏哦。
本文在 YOLOv8 测试 5 的基础上开展,在测试 5 中,实现了在 Linux 中 使用 Docker 部署 YOLOv8 模型,并借助 Python 封装 API 接口来调用。还介绍了 base64 格式图片的处理方法,最后通过接口上传图片的 base64 格式编码,得到接口返回识别结果。
本文在测试 5 基础上进行升级,采用 Dockerfile 的方式来构建 Conda 镜像,部署 YOLOv8 项目一键运行。
二、材料准备
材料准备:是在测试 5 基础上哦,这些材料的制作测试 5 都有详细说明。
在这里整理了一下步骤,方便快速操作。更详细的解释请参考,这篇文章
- 【测试 5 步骤 4-3】导出备份的 conda 虚拟环境 envs(envs / yolov8 里面安装了 python 和 pytorch);
- 【测试 5 步骤 3, 4-2】本地编写完成的 ultralytics-main 项目文件(base64_test.py 编写完成了);
- 把这两个材料放在同一个目录下,比如笔者放在了
/home/yuanyuan/build/yolo
目录下; /home/yuanyuan/build/yolo
是制作 Dockerfile 的工作目录。
1. 导出 conda 虚拟环境
制作虚拟环境
Docker 安装配置什么的这里就不赘述啦
用从 DockerHub 下载的基础镜像 conda/miniconda3 运行容器,制作 conda 虚拟环境 yolov8,并下载 python 和 pytorch。
# 1. 创建 conda 容器并运行
docker run -it --name yolopy03 conda/miniconda3 /bin/bash
# 2. 配置 yolov8 运行环境
conda create -n yolov8 python=3.9
# Proceed ([y]/n)? y
# 3. 检查虚拟环境配置
conda env list
# 4. 进入 base 环境
source activate
# 5. 激活 Conda 环境,创建 yolov8 运行
conda activate yolov8
# 6. 配置清华源镜像
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
# 7. 安装 pytorch
pip install torch==1.13.1+cpu torchvision==0.14.1+cpu torchaudio==0.13.1 \
--extra-index-url https://download.pytorch.org/whl/cpu
# 8. 检查 python 环境
python --version
# 9. 退出容器 exit,退出虚拟环境用 conda deactivate,退不出就 kill,没事的
exit
导出到 Linux 宿主机
备份 conda 虚拟环境 yolov8 到 Linux 宿主机
# docker cp 容器名:源路径 目标路径
docker cp yolopy03:/usr/local/envs /home/yuanyuan/conda
2. 编写 YOLOv8 项目并上传
自己电脑上,使用 PyCharm 打开从仓库下载的 YOLOv8 项目 ultralytics-main
,找到 tests 目录,在该目录下新建 base64_test.py
文件。并在 ultralytics-main/tests/tmp/
目录下,新建 upload
文件夹,用来存放接口上传的文件;新建 save
文件夹,用来存放项目保存的文件。
导入项目依赖
在 base64_test.py 文件中导入项目运行的所有依赖:
# YOLOv8 所需依赖
import contextlib
from copy import copy
from pathlib import Path
import cv2
import numpy as np
import pytest
import torch
import yaml
from PIL import Image
from torchvision.transforms import ToTensor
from ultralytics import RTDETR, YOLO
from ultralytics.cfg import TASK2DATA
from ultralytics.data.build import load_inference_source
from ultralytics.utils import (
ASSETS,
DEFAULT_CFG,
DEFAULT_CFG_PATH,
LINUX,
MACOS,
ONLINE,
ROOT,
WEIGHTS_DIR,
WINDOWS,
Retry,
checks,
is_dir_writeable,
)
from ultralytics.utils.downloads import download
from ultralytics.utils.torch_utils import TORCH_1_9, TORCH_1_13
MODEL = WEIGHTS_DIR / "path with spaces" / "yolov8n.pt" # test spaces in path
CFG = "yolov8n.yaml"
SOURCE = ASSETS / "bus.jpg"
TMP = (ROOT / "../tests/tmp").resolve() # temp directory for test files
IS_TMP_WRITEABLE = is_dir_writeable(TMP)
# Flask 框架使用所需依赖
from flask import Flask, request, send_file
# base64 处理依赖,文件依赖
import base64
from PIL import Image
from io import BytesIO
编写测试程序
在 base64_test.py 文件中,编写 API 接口,完成 YOLOv8 测试程序编写:
app = Flask(__name__)
@app.post('/baseFile')
def return_image():
# 1. 获取上传的文件
# 文件作为参数传递,其 id为 file
# 如果没有接收到这个请求,返回 No file part
if 'file' not in request.files:
return "No file part"
# 获取文件
file = request.files['file']
# 获取文件名
if file.filename == '':
return "No selected file"
filename = file.filename
# 2. 保存到指定位置 upload 文件夹
file.save(TMP / 'upload' / filename)
# 3. 获取编码文件并解码
base_file = TMP / 'upload' / filename
# 打开编码文件,读取文件中的内容
with open(base_file, 'r') as file:
content = file.read()
# 将 base64_str 以 “,” 分割为两部分,context 部分是需要解码的部分
base64_str = str(content)
head, context = base64_str.split(",")
# 解码时只要内容部分
img_data = base64.b64decode(context)
# 4. 通过解码内容得到图片,保存图片
image = Image.open(BytesIO(img_data))
image.save(TMP / 'save' / 'test_image.jpg')
# 5. 使用 YOLOv8 模型对该图片进行目标识别
model = YOLO(MODEL)
# 得到的图片路径
source = TMP / 'save' / 'test_image.jpg'
# 保存 目标识别的结果
results = model.predict(source, save=True, imgsz=320, conf=0.5)
# 6. 获取 识别结果 的保存路径
save_path = Path(results[0].save_dir)
image_path = save_path / 'test_image.jpg'
# 7. 以图片形式 返回结果
return send_file(image_path)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5001)
上传本地项目
本地项目 ultralytics-main 已经完成编写,关闭 PyCharm,找到 ultralytics-main 文件夹
通过 FinalShell,把 ultralytics-main 一整个上传到 Linux 服务器 /home/yuanyuan/build/yolo 目录中
3. 上传材料到工作目录
本地项目 ultralytics-main 应该是上一步就上传好了的,接下来把备份的虚拟环境也放进工作目录。
Linux 中拷贝文件夹的命令为:
# cp -r 源路径 目标路径
cp -r /home/yuanyuan/conda/envs /home/yuanyuan/build/yolo
如图所示,把这两个材料放在工作目录。
三、思路整理
Dockerfile 用于程序开发,就好比,本来我们是在 Linux 中运行官方仓库的基础镜像,然后自己在容器里面一步一步地完成 YOLOv8 模型的部署,自己创建 conda 环境,在命令行里一步一步地配置依赖,最后再通过 python 把我们的项目运行起来。
Dockerfile 要做的事情就是,上面的这些步骤都可以在构建镜像之前完成,然后只要运行这个镜像,项目就可以一键运行。
那么在 Dockerfile 中具体完成了哪些步骤呢?
- 配置基础镜像 conda/miniconda3
- 添加 ultralytics-main 项目到工作路径
- 添加适合 yolov8 运行的 conda 虚拟环境
- 设置合适的 Bash 脚本
/bin/bash -c
- 安装项目所需的依赖
- 配置工作路径
/usr/local/ultralytics-main
- 暴露项目运行的 5001 端口
- 设置容器默认的启动运行命令 CMD
四、部署 YOLOv8 项目
1. 编写 Dockerfile
根据上面的思路整理,完成 Dockerfile 的编写。
确定工作目录 /home/yuanyuan/build/yolo
,确保工作目录下面两份材料导入成功。
[root@localhost yolo]# pwd
/home/yuanyuan/build/yolo
[root@localhost yolo]# ls
envs ultralytics-main
在工作目录,创建 Dockerfile 文件:注意默认命名 Dockerfile 不要写错。
vim Dockerfile
编写 Dockerfile,注意顺序,构建的时候是从上到下执行的。
FROM conda/miniconda3
MAINTAINER yuanyuan<1234567@qq.com>
ADD ultralytics-main /usr/local/ultralytics-main
ADD envs /usr/local/envs
SHELL ["/bin/bash", "-c"]
RUN source activate && \
conda activate yolov8 && \
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
cd /usr/local/ultralytics-main && \
pip install -e . && \
pip uninstall opencv-python -y && \
pip install opencv-python-headless -i https://pypi.tuna.tsinghua.edu.cn/simple && \
pip install pytest && \
pip install flask
ENV MYPATH /usr/local/ultralytics-main
WORKDIR $MYPATH
EXPOSE 5001
CMD source activate && conda activate yolov8 && python tests/base64_test.py
2. 构建 + 运行 + 测试
构建镜像
在工作目录,使用 Dockerfile 构建 diy-yolov8 镜像
docker build -t diy-yolov8 .
一键运行
diy-yolov8 镜像构建完成后,把容器端口映射给宿主机,一键运行。
docker run -p 3354:5001 diy-yolov8
接口测试
测试方式,使用 Postman 测试。
在 Postman 中,输入宿主机 ip / 宿主机端口,POST 请求,添加 base64 格式编码 txt 文件,Send 测试!
http://ip:3354/baseFile
五、常见问题整理
1. sh 无法运行 source 命令
Docker 使用 conda 时,如果遇到以下错误:
ERROR: failed to solve: process "/bin/sh -c source ..." did not complete successfully: exit code: 127
错误原因:Docker 构建镜像时,默认使用 sh 方式,而 sh 下没有 source 命令。
解决方式:把 sh 修改为 bash 方式。
# 此命令写在 source 命令之前
SHELL ["/bin/bash", "-c"]
2. ADD 添加文件注意点
对比 cp 和 ADD 中的文件路径:
# 在 yolo 目录下放入 整个 envs
# 最终文件位置 yolo/envs
cp -r /home/yuanyuan/conda/envs /home/yuanyuan/build/yolo
# 把 envs 目录下的内容放入 local/envs 目录下
# 最终文件位置 local/envs
ADD envs /usr/local/envs
六、总结
本文在测试 5 基础上进行升级,采用 Dockerfile 的方式来构建 Conda 镜像,部署 YOLOv8 项目一键运行。整理了 Dockerfile 制作 YOLOv8 镜像过程中的常见问题。
一些参考资料
Docker 官方文档:https://docs.docker.com/engine/install/centos/
Docker 远程仓库:https://hub.docker.com/
FinalShell 下载:http://www.hostbuf.com/t/988.html
YOLOv8 官方文档:https://docs.ultralytics.com/zh/
YOLOv8 模型仓库地址:https://github.com/ultralytics/ultralytics
PyCharm官网:https://www.jetbrains.com/pycharm/download/?section=windows
Postman 官网:https://www.postman.com/
阿里云官网:https://www.aliyun.com/