ch3_6多线程举例

news2024/9/30 19:32:59

作者丨billom

来源丨投稿

编辑丨GiantPandaCV


云端深度学习的服务的性能加速通常需要算法和工程的协同加速,需要模型推理和计算节点的融合,并保证整个“木桶”没有太明显的短板。

如何在满足时延前提下让算法工程师的服务的吞吐尽可能高,尽可能简便成了性能优化的关键一环。为了解决这些问题,TorchPipe通过深入PyTorch的C++计算后端和CUDA流管理,以及针对多节点的领域特定语言建模,对外提供面向PyTorch前端的线程安全函数接口,对内提供面向用户的细粒度后端扩展。

开源地址:https://github.com/torchpipe/torchpipe

文档:https://torchpipe.github.io/zh/docs/introduction

背景

深度学习的Serving面临多个难题:

  • 一是GIL锁带来的多线程使用受限

  • 二是cpu-gpu异构设备开销和复杂性

  • 三是复杂流程

业界有一些实践,如triton inference server, 阿里妈妈high_service, 美团视觉GPU推理服务部署架构优化实践。总体上,有以下方向去做这些事情:

  • 全流程gpu化

  • DAG的并行化

  • 对于cpu计算后端,去克服GIL锁

通常用户对于trinton inference server的一个抱怨是,在多个节点交织的系统中,有大量业务逻辑在客户端完成,通过RPC调用服务端,很麻烦;而为了性能考虑,不得不考虑共享显存,ensemble,BLS[5]等非常规手段。

一. 问题定义

对于我们自己来说,面临的第一个问题是,pytorch 中如何并发调用resnet18模型。本项目开始于一个简单的需求,即我们需要求得一个 X,能够实现模型推理并满足:

  • 前向接口需要是线程安全的。

  • 在主要硬件平台(如 NVIDIA GPU)以及主要通用加速引擎(如 TensorRT/Libtorch)上实现了此 X。

import torch, X
resnet18 = X(model="resnet18_-1x3x224x224.onnx", 
                    precision="fp16",
                    max=4, 
                    instance_num=4, 
                    batching_timeout=5) 
data = torch.from_numpy(data)
net_output: torch.Tensor = resnet18(data=data)  # 线程安全调用

以此为起点,我们扩展到了对以下场景的支持:

  • 包含前处理在内的通用计算后端X的细粒度泛型扩展

  • 多节点组成的有向无环图(DAG)的流水线并行,多级结构化

  • 条件控制流

二. 背景知识

首先,我们介绍一些背景知识。您也可以跳过这一部分。

2.1 CUDA: 流和并发

CUDA提供了一致的抽象,来控制并发访问,以便用户最大化、完整地利用单块GPU设备的资源能力。为了最有效的使用GPU设备,我们希望:

- 单位硬件资源能承载更多的业务请求量

- GPU尽可能满载(前提:关联资源使用量小,时延达标)

为了达到此目的,我们简单分析下CUDA的编程模型。

硬件

Cuda Core是显卡主要的运算单元。 采用Pascal及以上架构的显卡拥有上千的CUDA核心,对应着多组SM(Streaming Multiprocessor),可共用于一个任务,也可承载不同的运算任务。从volta架构开始,NVIDIA引入了专为深度学习设计的Tensor Core. 在Turing架构的 Tesla T4中,一共有40个SM, 共享6MB的L2缓存。一个SM由64个FP32 算数单元,和8个Tensor Core组成。对于模型的算子级优化,需要关注较为底层的优化。而对于业务使用场景,既需要算子级优化(选取针对性的计算后端负责),也需要整体视角的分析。

参考链接: GPU Architecture.

CUDA流

CUDA流表示一个GPU操作队列,所有提交给GPU的任务,均指定了执行流。存在一个默认流,也就是`stream 0`, 作为默认的队列。提交任务这个操作本身可以是异步的,对流进行同步化,则意味着需要阻塞cpu线程,直至所有已经提交至该队列中的任务执行完毕。不同流之间的任务可以借助硬件的不同单元并行执行或者时分并发执行。

CUDA上下文(CUDA Context)

CUDA-Stream/CUDA-Context可以类比于线程/进程:多线程分配调用的GPU资源同属一个CUDA Context下,有自己的隔离的地址空间,资源不能跨Context共享。 默认情况下,一个进程中,在初次调用CUDA runtime软件库中的任何一个API时,会自动初始化当前进程中唯一的一个CUDA上下文。GPU在同一时刻只能切换到一个context,而默认情况下一个进程有一个上下文,故多个进程使用GPU,无法同时利用硬件。

虚拟化

由于GPU无法同时执行跨CUDA context的任务,导致硬件利用率可能不高,此时可采用一些虚拟化手段。典型的如NVIDIA官方的MPS(Multi Process Service),它实际上启动了一个独立进程去转发所有的任务。采用此方法的坏处是隔离性收到了一定破坏:一旦此进程失效,所有关联任务都将受到影响。

为了充分利用GPU的性能,可以采取一些措施:

- GPU任务合理分配到多个流,并只在恰当时机同步;

- 将单个显卡的任务限制在单个进程中,去克服CUDA上下文分时特性带来的资源利用率可能不足的问题。

2.2 PyTorch CUDA 语义

PyTorch 以易用性为核心,按照一致的原则组织了对GPU资源的访问。

当前流

在PyTorch内,当前流(current stream)指的是当前线程绑定的CUDA流。PyTorch通过以下API提供了绑定CUDA流到当前线程,以及获取当前线程绑定的CUDA流的功能:

torch.cuda.set_stream(stream)
torch.cuda.current_stream(device=None)

默认情况下,所有线程都绑定到默认流(stream 0)上. PyTorch的GPU运算均提交到当前线程绑定的当前流上。PyTorch尽量让用户感知不到这点:

- 通常来说,当前流是都是默认流,而在同一个流上提交的任务会按提交时间串行执行;

- 对于涉及到将GPU数据拷贝到CPU或者另外一块GPU设备的操作, PyTorch默认地在操作中插入当前流的同步操作 .

为了在多线程环境使得PyTorch充分利用GPU资源,我们需要打破以上惯例:

  • 计算后端线程绑定到独立的CUDA流;

  • 在线程转换时进行流同步

参考资料: asynchronous execution

更多信息,可参考https://torchpipe.github.io/zh/docs/preliminaries

三. 单节点的并行化

3.1 res****net18 计算加速

对于onnx格式的 resnet18的模型resnet18_-1x3x224x224.onnx, 通常有以下手段进行推理加速:

  • 使用tensorrt等框架进行模型针对性加速

  • 避免频繁显存申请

  • 多实例,batching,分别用来提高资源使用量和使用效率

  • 优化数据传输

线程安全的本地推理

为了方便,假设将tensorrt推理功能封装为名称为 TensorrtTensor 的计算后端。由于计算发生在gpu设备上,我们加上SyncTensor 表示gpu上的流同步操作。

| 配置项
| 参数
| 说明
|
| backend | “SyncTensor[TensorrtTensor]” | 计算后端和tensorrt推理本身一样,不是线程安全的。 |
| max
| 4 | 模型支持的最大batchsize,用于模型转换(onnx->tensorrt) |

torchpipe默认会在此计算后端上包裹一层可扩展的单节点调度后端,实现以下三个基本能力:

  • 前向接口线程安全性

  • 多实例并行

| 配置项
| 默认值
| 说明 |
| instance_num | 1 | 多个模型实例并行执行推理任务。 |

  • Batching

对于resnet18, 模型本身输入为-1x3x224x224, batchsize越大,单位硬件资源所完成的任务越多。batchsize 从计算后端(TensorrtTensor)读取。

| 配置项
| 默认值
| 说明 |
| batching_timeout | 0
| 单位为毫秒,在此时间内如果没有接收到 batchsize 个数目的请求,则放弃等待。 |

性能调优技巧

汇总以上步骤,我们获得推理resnet18在torchpipe下的必要参数:

import torchpipe as tp
import torch
config = {
# 单节点调度器参数:
"instance_num":2,
"batching_timeout":5,
# 计算后端:
"backend":"SyncTensor[TensorrtTensor]",
# 计算后端参数:
"model":"resnet18_-1x3x224x224.onnx",
"max":4 
}

# 初始化
models = tp.pipe(config)
data = torch.ones(1,3,224,224).cuda()

## 前向
input = {"data":data}
models(input) # <== 可多线程调用
result: torch.Tensor = input["result"] # 失败则 "result" 不存在

假设我们想要支持最多10路的客户端/并发请求, instance_num 一般设置2,以便最多有处理 instance_num*max = 8 路的能力。

性能取舍

请注意,我们的加速做了如下假设:

同设备上的数据拷贝(如cpu-cpu数据拷贝,gpu-gpu同一显卡内部显存拷贝)速度快,消耗资源少,整体上可忽略不计。

相对于cpu-gpu数据拷贝以及其他的计算,这条假设是没问题的。后面我们将看到,在一些特殊场景,这条假设可能不成立,需要相应的规避手段。

3.2 计算后端

在深度学习的服务中,如果仅支持模型加速远远不够。为此,我们内置了一些常用的细粒度后端。

内置后端举例:

|

名称

|

说明

|
|

DecodeMat

|

jpg解码

|
|

cvtColorMat

|

颜色空间转换

|
|

ResizeMat

|

resize

|
|

PillowResizeMat

|

严格保持和pillow的结果一致的resize

|
|

更多…

|
|

|

名称

|

说明

|
|

DecodeTensor

|

GPU上jpg解码

|
|

cvtColorTensor

|

颜色空间转换

|
|

ResizeTensor

|

resize

|
|

PillowResizeTensor

|

严格保持和pillow的结果一致的resize

|
|

更多…

|
|

3.3 Sequential

Sequential 能串联多个后端。也就是说,Sequential[DecodeTensor,ResizeTensor,cvtColorTensor,SyncTensor] 和 Sequential[DecodeMat,ResizeMat] 是有效后端。

在 Sequential[DecodeMat,ResizeMat] 的前向执行中,数据(dict)会依次经过下列流程:

  • 执行 DecodeMat:DecodeMat读取data, 并将结果赋值给result和color

  • 条件控制流:尝试将数据中的result的值赋值给data 并删除result

  • 执行 ResizeMat :ResizeMat读取data, 并将结果赋值给result键值

Sequential可简写为S.

3.4 单节点调度系统

输入数据经由默认的单节点调度系统BaselineSchedule分发给计算后端执行。在此过程中主要经历了凑batch和多实例的调度。

凑batch/多实例

对于TensorrtTensor等模型推理引擎,输入范围一般是[1, max_batch_size], 此时调度系统可将输入数据打包送入。BaselineSchedule单节点调度后端实现了如下的调度功能:

  • 根据instance_num参数启动多个计算后端实例

  • 从计算后端读取max_batch_size=max(), 如果大于1,启动凑batch功能

  • 输入队列获取数据,在batching_timeout的时间内,如果获得了max_batch_size个数据,那么将其送往Batch队列, 如果时间到了仍然没有获得足够数据,那么将已有数据送入Batch队列

  • 将任务从Batch队列中分发到空闲的计算实例中。

以上是主干的大致流程,细节部分会有差别,如BaselineSchedule也实现了基础的自适应流量功能,根据多实例计算引擎的状态决定batch状态的功能,以及组合调度的功能。

单节点组合调度

有些计算后端的输入范围最小值大于1, 导致无法作为正常的后端进行调度(可能导致有些数据永远没有办法进行处理)。BaselineSchedule通过&符号提供了组合的能力。

举例来讲,对于TensorrtTensor后端,一些模型不方便转为动态模型, 此时可以用一个 batchsize=1 的模型和几个 batchsize=N 的模拟动态batch.

[model]
model="batch1.onnx&batch4.onnx&batch8.onnx"
backend="SyncTensor[TensorrtTensor]" # or 'SyncTensor[TensorrtTensor]&SyncTensor[TensorrtTensor]'
instance_num = 2 # auto extend to '2&2&2'
min="1&4&8"
max="1&4&8"

此时,将共有6个实例,前两个实例输入范围均是[1, 1],中间两个均是[4, 4],最后两个均是[8, 8]。对BaselineSchedule来说,这六个实例组成了两个虚拟实例,每个虚拟实例占用了三个实例,虚拟实例的输入范围是[1, 8].

更多信息,可参考https://torchpipe.github.io/zh/docs/Intra-node

四. 多节点调度

针对多节点,主要考虑了**:**

多个节点的链接,

filter: 有向无环图中的条件控制流,

context: 自动map语法糖,

图的跳转,

逻辑节点。

限于篇幅,暂时不再展开。可参考https://torchpipe.github.io/zh/docs/Inter-node

五. RoadMap

torchpie目前处于一个快速迭代阶段,我们非常需要你的帮助。欢迎通过issues或者反馈等方式帮助我们。

我们的最终目标是让服务端高吞吐部署尽可能简单。为了实现这一目标,我们将积极自我迭代,也愿意参与有相近目标的其他项目。

2023年度和2024年度 RoadMap

  • 大模型方面的示例

  • 公开的基础镜像和pypi(manylinux)

  • 优化编译系统,分为core,pplcv,model/tensorrt,opencv等模块

  • 基础结构优化。包含python与c++交互,异常,日志系统,跨进程后端的优化;

  • 技术报告

潜在未完成的研究方向

  • 单节点调度和多节点调度后端,他们与计算后端无本质差异,需要更多面向用户进行解耦,我们想要将这部分优化为用户API的一部分;

  • 针对多节点的调试工具。由于在多节点调度中,使用了模拟栈设计,比较容易设计节点级别的调试工具;

  • 负载均衡

六. 意见和建议

欢迎大家提出意见,微信:billom,备注torchpipe

参考链接

  • [1] PyTorch’s Philosophy.

  • [2] GPU Architecture

  • [3] PyTorch’s Asynchronous Execution

  • [4] triton inference server

  • [5] Business Logic Scripting

  • [6] Walle: An End-to-End, General-Purpose, and Large-Scale Production System for Device-Cloud Collaborative Machine Learning | PDF, Github

  • [7] Using Python for Model Inference in Deep Learning. Zachary DeVito et al. (2021)

ref

原文出自;

GiantPandaCV

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

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

相关文章

Photoshop2024磨皮滤镜插件Portraiture

想要快速提升人像修图效果&#xff0c;让皮肤看起来更加光滑细腻吗&#xff1f;那么你可以尝试使用Photoshop磨皮滤镜插件。这些插件能够让你在短时间内快速有效地进行人像处理&#xff0c;无论是对于专业的设计师还是初学者来说都是非常实用的工具。 接下来&#xff0c;让我为…

AI时代中小企业算力需求爆发,惠普发布新品战99 Monster满血高算工作站

第17届DEMO CHINA创新中国峰会10月25日至26日在北京举行&#xff0c;吸引了国内众多优秀创新创业项目的积极参与。作为本届DEMO CHINA独家战略合作伙伴&#xff0c;惠普在大会上正式发布战家族新品战99 Monster满血高算工作站&#xff0c;满足AI时代中小企业对于算力的爆发式需…

Live800:客服中心质检管理的五大方法

客服中心质检管理是企业提供优质服务和客户满意度的关键。因此&#xff0c;企业必须采用适当的方法来管理客服质检以确保服务质量。本文将介绍客服中心质检管理的五大方法。 1、建立清晰的服务标准 建立清晰的服务标准是提高客服质量的关键因素。服务标准可以包括快速响应时间…

TypeScript详解

一、是什么 TypeScript 是 JavaScript 的类型的超集&#xff0c;支持ES6语法&#xff0c;支持面向对象编程的概念&#xff0c;如类、接口、继承、泛型等 超集&#xff0c;不得不说另外一个概念&#xff0c;子集&#xff0c;怎么理解这两个呢&#xff0c;举个例子&#xff0c;如…

广受欢迎的 VLC Media Player 开源媒体播放器软件已更新到 3.0.19 版

导读广受欢迎的 VLC Media Player 开源媒体播放器软件已更新到 3.0.19 版&#xff0c;这是继 VLC 3.0.18 发布近一年后的又一版本&#xff0c;其中包含大量改进和错误修复。 VLC 3.0.19 版本的亮点包括改进了软件解码对 AV1 HDR 的支持&#xff0c;支持 WAV 音频文件的 RIFF IN…

基于SSM的罪犯信息管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

数字化工厂:连接、集成与数据融合

随着科技的不断发展&#xff0c;数字化工厂管理系统逐渐成为制造业的重要趋势。数字化工厂的核心在于连接、集成与数据融合&#xff0c;通过这些技术手段&#xff0c;实现对设备、生产线、工厂、供应商、产品、客户等各个环节的全面优化&#xff0c;提升企业的生产效率和产品质…

字符串中的assert和strcat

assert&#xff1a;函数原型是&#xff1a;void assert( int expression );其作用是现计算表达式 expression &#xff0c;如果其值为假(即为0)&#xff0c;那么它先 stderr 打印一条出信息,然后通过调用 abort 来终止程序运行。使用assert 的缺点是&#xff0c;频繁的调用会影…

GoLong的学习之路(十二)语法之标准库 flag的使用

上回书说到&#xff0c;fmt的标准库的一些常用的使用函数。这次说flag的使用&#xff0c;以下这些库要去做了解。不然GG&#xff0c;Go语言内置的flag包实现了命令行参数的解析&#xff0c;flag包使得开发命令行工具更为简单。 文章目录 os.Argsflag包flag.Type()flag.TypeVar(…

AI口语APP的实现

AI口语应用程序是一种借助人工智能技术&#xff0c;旨在帮助用户提高口语能力、练习语言技能以及进行交流和学习语言的应用程序。这类应用通常提供以下主要功能&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交…

Ansys Speos | SPEOS 在HUD杂光分析中的应用

概述 随着汽车智能座舱的普及&#xff0c;HUD的装车率也随之增加&#xff0c;未来也可能会成为车内座舱的标配。而HUD是一个由光学&#xff0c;机械&#xff0c;电子&#xff0c;软件组成的复杂的高科技产品&#xff0c;其所在的汽车座舱是很复杂的环境。我们需要对HUD进行诸如…

2023年05月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 可以对Python代码进行多行注释的是&#xff1f;&#xff08; &#xff09; A: # B: " " C: ‘’’ ‘’’…

Java关于实例对象调用静态变量和静态方法问题

直接去看原文 原文链接:Java关于实例对象调用静态变量和静态方法问题_java对象可以调用static方法吗_骑个小蜗牛的博客-CSDN博客 --------------------------------------------------------------------------------------------------------------------------------- 实例…

2.13每日一题(根号下的定积分及去绝对值的定积分)

1、用三角函数的公式化1及二倍角公式将sinx化掉&#xff0c;构成完全平方公式 2、去根号&#xff0c;注意去根号要加绝对值&#xff0c; 3、通过区间比较sinx、cosx的大小去绝对值

vscode 保存 “index.tsx“失败: 权限不足。选择 “以超级用户身份重试“ 以超级用户身份重试。

vscode 保存 "index.tsx"失败: 权限不足。选择 “以超级用户身份重试” 以超级用户身份重试。 操作&#xff1a;mac在文件夹中创建文件&#xff0c;sudo 创建umiJs项目 解决&#xff1a;修改文件夹权限 右键文件夹

浮点数的表示与运算

一、浮点数的表示 1、规格化浮点数的特点 2、浮点数表示

C#上位机序列10: 批量读写+点对点更新+数据类型处理

一、源码结构 二、运行效果 三、源码解析 PLC批量读写点对点更新数据类型处理 优点&#xff1a;根据数据类型&#xff0c;判定监听的地址范围&#xff08;40120_int 监听两个word&#xff1a;40120 40121&#xff1b;40130_long 监听四个word&#xff1a;40130 40131 40132 4…

运营商光纤资源管理:管理工具的力量

随着通信信息化水平发展&#xff0c;光纤资源已成为现代通信网络的核心要素之一。然而&#xff0c;管理却面临诸多挑战&#xff0c;尤其对于电信运营商而言&#xff0c;面对庞大而复杂的光纤网络资源&#xff0c;怎样做到既不浪费现有资源&#xff0c;又能满足未来业务需求&…

18亿欧元大动作,法国瞄准实现量子飞跃

Quobly 正在开发一种容错量子处理器&#xff08;图片来源&#xff1a;网络&#xff09; 2021年1月&#xff0c;马克龙总统宣布了法国国家量子计算计划&#xff0c;并将为该技术投入高达18亿欧元。 “量子战略至关重要&#xff0c;”马克龙在量子研究中心巴黎萨克雷大学宣布该…

概念解析 | 功率放大器与低噪声放大器:一场关于信号放大的对比

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:功率放大器(PA)与低噪声放大器(LNA)。 功率放大器与低噪声放大器:一场关于信号放大的对比 一、背景介绍 在现代的通信系统中,功率放大器 (Power Amplifier, PA)与低噪声放…