【深度学习】ONNX模型多线程快速部署【基础】

【深度学习】ONNX模型CPU多线程快速部署【基础】

提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论

文章目录

  • 【深度学习】ONNX模型CPU多线程快速部署【基础】
  • 前言
  • 搭建打包环境
  • python多线程并发简单教程
    • 基本教程
    • ONNX模型多线程并发
  • 打包成可执行文件
  • 总结


前言

之前的内容已经尽可能简单、详细的介绍CPU【Pytorch2ONNX】和GPU【Pytorch2ONNX】俩种模式下Pytorch模型转ONNX格式的流程,本博文根据自己的学习和需求进一步讲解ONNX模型的部署。onnx模型博主将使用PyInstaller进行打包部署,PyInstaller是一个用于将Python脚本打包成独立可执行文件的工具,【入门篇】中已经进行了最基本的使用讲解。之前博主在【快速部署ONNX模型】中分别介绍了CPU模式和GPU模式下onnx模型打包成可执行文件的教程,本博文将进一步介绍在CPU模式下使用多线程对ONNX模型进行快速部署。
系列学习目录:
【CPU】Pytorch模型转ONNX模型流程详解
【GPU】Pytorch模型转ONNX格式流程详解
【ONNX模型】快速部署
【ONNX模型】多线程快速部署


搭建打包环境

创建一个纯净的、没有多余的第三方库和模块的小型Python环境,抛开任何pytorch相关的依赖,只使用onnx模型完成测试。

# name 环境名、3.x Python的版本
conda create -n deploy python==3.10
# 激活环境
activate deploy 
# 安装onnx
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple onnx
# 安装GPU版
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple onnxruntime-gpu==1.15.0
# 下载安装Pyinstaller模块
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Pyinstaller
# 根据个人情况安装包,博主这里需要安装piilow
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple Pillow

python多线程并发简单教程

多线程是一种并发编程的技术,通过同时执行多个线程来提高程序的性能和效率。python的内置模块提供了两个内置模块:thread和threading,thread是源生模块,是比较底层的模块,threading是扩展模块,是对thread做了一些封装,可以更加方便的被使用,所以只需要使用threading这个模块就能完成并发的测试。

基本教程

python3.x中通过threading模块有两种方法创建新的线程:通过threading.Thread(Target=executable Method)传递给Thread对象一个可执行方法(或对象);通过继承threading.Thread定义子类并重写run()方法。下面给出了俩种创建新线程方法的例子,读者可以运行一下加深理解。

  • 普通创建方式:threading.Thread进行创建多线程
    import threading
    import timedef myTestFunc():# 子线程开始print("the current threading %s is runing" % (threading.current_thread().name))time.sleep(1)   # 休眠线程# 子线程结束print("the current threading %s is ended" % (threading.current_thread().name))# 主线程
    print("the current threading %s is runing" % (threading.current_thread().name))
    # 子线程t1创建
    t1 = threading.Thread(target=myTestFunc)
    # 子线程t2创建
    t2 = threading.Thread(target=myTestFunc)t1.start()  # 启动线程
    t2.start()t1.join()  # join是阻塞当前线程(此处的当前线程时主线程) 主线程直到子线程t1结束之后才结束
    t2.join()
    # 主线程结束
    print("the current threading %s is ended" % (threading.current_thread().name))
    
  • 自定义线程:继承threading.Thread定义子类创建多线
    import threading
    import timeclass myTestThread(threading.Thread):  # 继承父类threading.Threaddef __init__(self, threadID, name, counter):threading.Thread.__init__(self)self.threadID = threadIDself.name = name# 把要执行的代码写到run函数里面,线程在创建后会直接运行run函数def run(self):print("the current threading %s is runing" % (self.name))print_time(self.name,5*self.threadID)print("the current threading %s is ended" % (self.name))def print_time(threadName, delay):time.sleep(delay)print("%s process at: %s" % (threadName, time.ctime(time.time())))# 主线程
    print("the current threading %s is runing" % (threading.current_thread().name))# 创建新线程
    t1 = myTestThread(1, "Thread-1", 1)
    t2 = myTestThread(2, "Thread-2", 2)# 开启线程
    t1.start()
    t2.start()# 等待线程结束
    t1.join()
    t2.join()print("the current threading %s is ended" % (threading.current_thread().name))
    

ONNX模型多线程并发

博主采用的是基础教程中普通创建方式创建新线程:将推理流程单独指定成目标函数,而后创建线程对象并指定目标函数,同一个推理session被分配给多个线程,多个线程会共享同一个onnx模型,这是因为深度学习模型的参数通常存储在模型对象中的共享内存中,并且模型的参数在运行时是可读写的,每个线程可以独立地使用模型对象执行任务,并且线程之间可以共享模型的状态和参数。

import onnxruntime as ort
import numpy as np
from PIL import Image
import time
import datetime
import sys
import os
import threadingdef composed_transforms(image):mean = np.array([0.485, 0.456, 0.406])  # 均值std = np.array([0.229, 0.224, 0.225])  # 标准差# transforms.Resize是双线性插值resized_image = image.resize((args['scale'], args['scale']), resample=Image.BILINEAR)# onnx模型的输入必须是np,并且数据类型与onnx模型要求的数据类型保持一致resized_image = np.array(resized_image)normalized_image = (resized_image/255.0 - mean) / stdreturn np.round(normalized_image.astype(np.float32), 4)def check_mkdir(dir_name):if not os.path.exists(dir_name):os.makedirs(dir_name)args = {'scale': 416,'save_results': True
}
def process_img(img_list,ort_session,image_path,mask_path,input_name,output_names):for idx, img_name in enumerate(img_list):img = Image.open(os.path.join(image_path, img_name + '.jpg')).convert('RGB')w, h = img.size#  对原始图像resize和归一化img_var = composed_transforms(img)# np的shape从[w,h,c]=>[c,w,h]img_var = np.transpose(img_var, (2, 0, 1))# 增加数据的维度[c,w,h]=>[bathsize,c,w,h]img_var = np.expand_dims(img_var, axis=0)start_each = time.time()prediction = ort_session.run(output_names, {input_name: img_var})time_each = time.time() - start_each# 除去多余的bathsize维度,NumPy变会PIL同样需要变换数据类型# *255替换pytorch的to_pilprediction = (np.squeeze(prediction[3]) * 255).astype(np.uint8)if args['save_results']:Image.fromarray(prediction).resize((w, h)).save(os.path.join(mask_path, img_name + '.jpg'))def main():# 线程个数num_cores = 10# 保存检测结果的地址input = sys.argv[1]# providers = ["CUDAExecutionProvider"]providers = ["CPUExecutionProvider"]model_path = "PFNet.onnx"ort_session = ort.InferenceSession(model_path, providers=providers)  # 创建一个推理sessioninput_name = ort_session.get_inputs()[0].name# 输出有四个output_names = [output.name for output in ort_session.get_outputs()]print('Load {} succeed!'.format('PFNet.onnx'))start = time.time()image_path = os.path.join(input, 'image')mask_path = os.path.join(input, 'mask')if args['save_results']:check_mkdir(mask_path)# 所有图片数量img_list = [os.path.splitext(f)[0] for f in os.listdir(image_path) if f.endswith('jpg')]# 每个线程被均匀分配的图片数量total_images = len(img_list)start_index = 0images_per_list = total_images // num_cores# 理解成线程池Thread_list = []for i in range(num_cores):end_index = start_index + images_per_listimg_l = img_list[start_index:end_index]start_index = end_index# 分配线程t = threading.Thread(target=process_img, args=(img_l,ort_session, image_path, mask_path,input_name,output_names))# 假如线程池Thread_list.append(t)# 线程执行t.start()# 这里是为了阻塞主线程for t in Thread_list:t.join()end = time.time()print("Total Testing Time: {}".format(str(datetime.timedelta(seconds=int(end - start)))))
if __name__ == '__main__':main()

线程的数量根据需求而定,不是越多越好。


打包成可执行文件

  • 在cpu模式下打包可执行文件:
    pyinstaller -F run_t.py
    
  • 在gpu模式下打包可执行文件:
    pyinstaller -F run_t.py --add-binary "D:/ProgramData/Anaconda3_data/envs/deploy/Lib/site-packages/onnxruntime/capi/onnxruntime_providers_cuda.dll;./onnxruntime/capi" --add-binary "D:/ProgramData/Anaconda3_data/envs/deploy/Lib/site-packages/onnxruntime/capi/onnxruntime_providers_shared.dll;./onnxruntime/capi"
    

    详细的过程和结果此前已经讲解过了,可以查看博主的博文【快速部署ONNX模型】。图片数量较多时,对比此前的执行速度,多线程的执行速度快了俩倍以上。

总结

尽可能简单、详细的介绍ONNX模型多线程快速部署过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/87286.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springboot实战(七)之jackson配置前后端交互下划线转驼峰对象序列化与反序列化

目录 环境: 1.驼峰转下划线配置 1.1单个字段命名转化使用JsonProperty注解 1.2单个类进行命名转化 3.全局命名策略配置 2. 序列化以及反序列化 2.1序列化 2.2反序列化 3.自定义序列化与反序列化 在Web开发中,JSON(JavaScript Obje…

【Zblog搭建博客网站】windows环境搭建属于自己的博客并发布上线 - cpolar内网穿透

文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员,自己搭建网站制作网页是绕…

数据结构题型10-链栈

//参考博客&#xff1a;https://blog.csdn.net/weixin_37716512/article/details/104068102 #include <iostream> //引入头文件 using namespace std;typedef int Elemtype;#define Maxsize 10 #define ERROR 0 #define OK 1typedef struct Linknode {Elemtype data;…

DS18B20温度传感器

DS18B20简介 DS18B20 是由 DALLAS 半导体公司推出的一种的“一线总线&#xff08;单总线&#xff09;”接口的温度传感器 这种一线总线就是 三线制 SPI DS18B20的 配置寄存器&#xff1a; TM 是测试位&#xff0c;出厂设置就被设置为0&#xff0c;不需要改动&#xff0c; R1、R…

企业架构LNMP学习笔记61

Nginx作为tomcat的前段反向代理&#xff1a; 在实际业务环境中&#xff0c;用户是直接通过域名访问&#xff0c;基于协议一般是http、https等。默认tomcat运行在8080端口。一般会通过前端服务器反向代理到后端的tomcat的方式&#xff0c;来实现用户可以通过域名访问tomcat的we…

微信收款码费率0.38太坑了

作为一个有多年运营经验的商家&#xff0c;我本人在申请收款功能时曾经走过了不少弯路。我找遍了市面上的知名的支付公司&#xff0c;但了解到的收款手续费率通常都在0.6左右&#xff0c;最低也只能降到0.38。这个过程吃过不少苦头。毕竟&#xff0c;收款功能是我们商家的命脉&…

AI聊天ChatGPT系统源码卡密验证开源版

ChatGPT卡密验证版源码是一个基于PHP7.4和MySQL5.6的聊天AI源码&#xff0c;它不仅支持暗黑模式、反应速度极快&#xff0c;而且充值方面采用后台生成卡密方式&#xff0c;方便快捷&#xff0c;如果您有能力将其接入在线支付&#xff0c;即可进一步拓展充值方式&#xff0c;为更…

KMeans算法全面解析与应用案例

目录 一、聚类与KMeans介绍聚类的基础概念KMeans算法的重要性 二、KMeans算法原理数据集和特征空间距离度量算法步骤 三、KMeans案例实战案例背景&#xff1a;客户细分数据集说明Python实现代码输出与解释 四、KMeans的优缺点优点计算效率高算法简单易于实现 缺点需要预设K值对…

一、机器学习基础知识:基本概念与Python开发环境

文章目录 1、机器学习的不同类型1.1 监督学习1.2 无监督学习1.3 强化学习 2、Python开发环境2.1 Python第三方库2.2 AnacondaPycharm集成开发环境 1、机器学习的不同类型 机器学习属于人工智能的一个分支&#xff0c;专门用于对数据进行自动分析以发现相关规律&#xff0c;从而…

视频监控/视频汇聚/安防视频监控平台EasyCVR配置集群后有一台显示离线是什么原因?

开源EasyDarwin视频监控TSINGSEE青犀视频平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;在视频监控播放上&#xff0c;TSINGSEE青犀视频安防监控汇聚平台可支持1、4、9、16个画面窗口播放&#xff0c;可同时播放多…

芯片验证就是一次旅行

如果你国庆希望去一个你不曾去过的城市旅行&#xff0c;比如“中国苏州”。对游客来说&#xff0c;它是个蛮大的城市&#xff0c;有许多景点可以游玩&#xff0c;还有许多事情可以做。但实际上&#xff0c;即使最豪也最清闲的游客也很难看苏州的所有方方面面。同样的道理也适用…

肖sir__mysql中数据库后端无法展示

mysql中数据库后端无法展示&#xff1a; 错误现象 解决方法&#xff1a; mysql中数据库后端无法展示&#xff1a;my.cnf (5,7数据库) 在 mysql 配置文件中加入&#xff1a; sql_modeNO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES 或者重启数据库

Android Kotlin 基础详解

1,基础语法 1.1 可变变量与不可变变量 可以多次赋值的变量是可变变量&#xff0c;用关键字var表示&#xff1a; var <标识符> : <类型> <初始化值> 注意&#xff0c;在kotlin中成员变量不会赋默认值&#xff0c;不像java一样&#xff0c;必须手动添加默…

Android12之容器类SortedVector、KeyedVector、Vector、VectorImpl总结(一百六十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

「大数据-2.1」HDFS集群启停命令

目录 一、HDFS集群一键启停脚本 1. HDFS集群的一键启动脚本 2. HDFS集群的一键关闭脚本 二、单进程启停 1. hadoop-daemon.sh脚本 2. hdfs脚本 三、总结 1. 一键启停脚本 2. 独立进程启停 一、HDFS集群一键启停脚本 Hadoop HDFS组件内置了HDFS集群的一键启停脚本。 1. HDFS集群…

ubuntu20.04 jammy 安装ros2

ubunut22.04 jammy&#xff08;5.15&#xff09; ros2版本: humble 安装参考&#xff1a; Ubuntu (Debian packages) — ROS 2 Documentation: Humble documentationl 按照官方给的操作指南进行操作即可&#xff0c;到安装软件包的时候&#xff0c;若只为开发&#xff0…

【LeetCode热题100】--56.合并区间

56.合并区间 排序&#xff1a; 如果按照区间的左端点排序&#xff0c;那么在排完序的列表中&#xff0c;可以合并的区间一定是连续的&#xff0c;如下图所示&#xff0c;标记为蓝色、黄色和绿色的区间分别可以合并为一个大区间&#xff0c;它们在排完序的列表中是连续的 算法&a…

安科瑞AMC16-DETT铁塔jizhan直流电能计量模块,直流计量用

安科瑞虞佳豪壹捌柒陆壹伍玖玖零玖叁 9月20日&#xff0c;在杭州亚运会火炬传递的现场&#xff0c;不少人通过网络与亲友连线&#xff0c;共同见证火炬传递的历史时刻。上午6时&#xff0c;杭州铁塔的一线通信保障人员共27人就已经在本次火炬传递收官点位奥体中心西广场附近&a…

【操作系统笔记九】并发安全问题

用户态抢占和内核态抢占 内核中可以执行以下几种程序&#xff1a; ① 当前运行的进程&#xff1a;陷阱程序&#xff08;系统调用&#xff09; 和 故障程序&#xff08;page fault&#xff09; &#xff0c;进程运行在内核态的时候&#xff0c;其实就是在执行进程在用户态触发的…

关于安卓SVGA浅尝(一)svgaplayer库的使用

关于安卓SVGA浅尝&#xff08;一&#xff09;使用 相关链接 SVGA官网 SVGA-github说明文档 背景 项目开发&#xff0c;都会和动画打交道&#xff0c;动画的方案选取&#xff0c;就有很多选择。如Json动画&#xff0c;svga动画&#xff0c;gif等等。各有各的优势。目前项目中…