首页 > 其他分享 >模型的预处理操作应该部署在哪里?

模型的预处理操作应该部署在哪里?

时间:2022-11-16 11:13:45浏览次数:58  
标签:部署 text 模型 ids send time 预处理 服务端

前言

这两天在做一个事情:使用 NVIDIA Triton 将训练好的文本分类模型 BERT + TextCNN 部署到服务器上。部署模型的过程中,发现模型的输入预处理操作,可以部署到客户端上,也可以部署到服务端上。因此,有了本文的标题,模型的预处理操作应该部署在哪里?

对于文本分类模型,预处理操作需要进行分词,将一个句子变成一个一个单词。除了文本分类模型,其他模型可能还需要后处理操作,比如目标检测模型需要 NMS,去除掉重叠的框框。这些模型的预处理、后处理操作应该部署在哪里呢?

对于这个问题,需要仔细考虑 tradeoff,部署到服务端有什么好处、坏处?部署到客户端又有什么好处、坏处?再根据具体模型,具体的部署环境,做出选择。

tradeoff

部署到服务端

优点

  1. 从调用者的角度来看,部署到服务端可以获得一个统一的 API 入口,调用者无需关注内部实现。
  2. 接着第一点,模型的迭代更新,预处理后处理操作可能发生改变,统一的 API 将无需更新客户端。
  3. 服务端性能高、速度快,软件环境齐全。

缺点

  1. 增加服务器负载。
  2. 原始数据可能很大,经过预处理操作之后,数据传输量变小。传原始数据的时间会更长。

部署到客户端

优点

  1. 充分利用客户端性能,减少服务器负载。

缺点

  1. 客户端需要知道预处理的逻辑,或者服务端需要为每一种语言提供 SDK。
  2. 预处理的速度受到客户端设备的影响,可能预处理的速度太慢,导致整体推理时间变长。
  3. 客户端的机器上,不一定有预处理操作需要的环境。

实验

本节通过实验,对比预处理操作放在客户端和服务端的性能差异。在部署前,将 torch 训练好的模型,导出成 ONNX,然后转换成 tensorrt/openvino 模型。另外,模型的预处理操作,依赖了 transformers/tokenizers,需要 pip 安装 tokenizers,然后分别开发客户端和服务端的逻辑。

实验设置 1.1:将预处理放在客户端,服务端部署一个 tensorrt 模型。

实验设置 1.2:将预处理操作部署到服务端,服务端部署 tensorrt 模型和预处理模型,并使用 triton ensemble 特性搭建数据处理流水线。

实验设置 2.1:将预处理放在客户端,服务端部署一个 openvino 模型。

实验设置 2.2:将预处理操作部署到服务端,服务端部署 openvino 模型和预处理模型,并使用 triton ensemble 特性搭建数据处理流水线。

实验结果

send ids 表示客户端预处理后发送 ids,send str 表示客户端直接发送 string。

1.1 和 1.2 的结果:
send ids time cost:  0.006104469299316406 [[-2.2179837  2.3859138]]
send str time cost:  0.007252931594848633 [[-2.2179837  2.3859138]]

2.1 和 2.2 的结果:
send ids time cost:  0.02684760093688965 [[-2.217986   2.3859158]]
send str time cost:  0.027203798294067383 [[-2.217986   2.3859158]]

实验结果分析

我们可以看到,不管是 GPU 还是 CPU,预处理操作放在服务端会变慢一点。初步怀疑是数据传输导致的速度变慢。

进一步实验

将发送到服务端的 string 复制几份,让文本变长。同时也实验了文本只发送一个 "great!" 这样的超短文本。

"great!" 的结果:
send ids time cost:  0.0056743621826171875 [[-1.4489281  1.5539637]]
send str time cost:  0.005866050720214844 [[-1.4489281  1.5539637]]

复制几份的结果:
send ids time cost:  0.009465217590332031 [[-2.2179837  2.3859138]]
send str time cost:  0.012185335159301758 [[-2.2179837  2.3859138]]

这一组实验结果表明:

  1. triton ensemble 存在 overhead,预处理操作即使放在服务端,在文本变短、数据量发送变少的情况,也仍然会慢一点。
  2. 预处理放在客户端可以减少数据发送量,减少数据传输的延时。

总结

预处理操作放在哪里,要看具体的部署场景。一般来说,部署到服务端的好处是更加统一,方便升级。部署到客户端的好处是,充分利用边缘设备的性能。

实验代码

完整的项目看这个地方,从训练到部署:https://github.com/zzk0/models/tree/main/nlp/text-classification

import time
import numpy as np
import tritonclient.http as httpclient
from tokenizers import Tokenizer


device_to_service = {
    'cpu': ['text_cnn_bert_openvino', 'text_cnn_bert_pipeline_cpu'],
    'gpu': ['text_cnn_bert_tensorrt', 'text_cnn_bert_pipeline'],
}

tokenizer = Tokenizer.from_file('./pretrained/bert-base-cased/tokenizer.json')
tokenizer.enable_truncation(max_length=128)
tokenizer.enable_padding(length=128)


def preprocess(text: str):
    inputs = tokenizer.encode_batch(text)
    inputs_ids = []
    for input in inputs:
        inputs_ids.append(input.ids)
    inputs_ids = np.array(inputs_ids).astype(np.int32)
    return inputs_ids


def send_ids(triton_client, text: str, device: str = 'gpu'):
    input_ids = preprocess(text)
    inputs = []
    inputs.append(httpclient.InferInput('input', input_ids.shape, "INT32"))
    inputs[0].set_data_from_numpy(input_ids, binary_data=False)
    outputs = []
    outputs.append(httpclient.InferRequestedOutput('output', binary_data=False))
    results = triton_client.infer(device_to_service[device][0], inputs=inputs, outputs=outputs)
    output_data0 = results.as_numpy('output')
    return output_data0


def send_text(triton_client, text: str, device: str = 'gpu'):
    text_bytes = []
    for sentence in text:
        text_bytes.append(str.encode(sentence, encoding='UTF-8'))
    text_np = np.array([text_bytes], dtype=np.object_)
    inputs = []
    inputs.append(httpclient.InferInput('input', text_np.shape, "BYTES"))
    inputs[0].set_data_from_numpy(text_np, binary_data=False)
    outputs = []
    outputs.append(httpclient.InferRequestedOutput('output', binary_data=False))
    results = triton_client.infer(device_to_service[device][1], inputs=inputs, outputs=outputs)
    output_data0 = results.as_numpy('output')
    return output_data0



if __name__ == '__main__':
    device = 'gpu'

    triton_client = httpclient.InferenceServerClient(url='127.0.0.1:8000')
    text = ["I went and saw this movie last night after being coaxed to by a few friends of mine. I'll admit that I was reluctant to see it because from what I knew of Ashton Kutcher he was only able to do comedy. I was wrong. Kutcher played the character of Jake Fischer very well, and Kevin Costner played Ben Randall with such professionalism. The sign of a good movie is that it can toy with our emotions. This one did exactly that. The entire theater (which was sold out) was overcome by laughter during the first half of the movie, and were moved to tears during the second half. While exiting the theater I not only saw many women in tears, but many full grown men as well, trying desperately not to let anyone see them crying. This movie was great, and I suggest that you go see it before you judge."]

    _ = send_ids(triton_client, text, device)
    t0 = time.time()
    res = send_ids(triton_client, text, device)
    t1 = time.time()
    print('send ids time cost: ', t1 - t0, res)

    _ = send_text(triton_client, text, device)
    t0 = time.time()
    res = send_text(triton_client, text, device)
    t1 = time.time()
    print('send str time cost: ', t1 - t0, res)

标签:部署,text,模型,ids,send,time,预处理,服务端
From: https://www.cnblogs.com/zzk0/p/16894787.html

相关文章

  • Almalinux安装部署kubesphere容器云平台
    一、介绍AlmaLinux是一个开源的、社区驱动的项目,旨在填补CentOS稳定版本消亡所留下的空白。AlmaLinux是RHEL8的一个1:1二进制兼容的分支,它是由有丰富经验的CloudLinuxOS......
  • 实施部署(锐捷云桌面篇)
    大家好,我是小杜,打工人“快乐”的学习的一天又开始了!感觉自己是一个“无情”的学习机器,设备的学习,公司流程的学习。不过师傅一直在夸我学得很快,会很快出师的。怎么会有......
  • 三分钟梳理TDengine安装部署的逻辑
      ​小T导读:TDengine,是涛思数据面对高速增长的物联网大数据市场和技术挑战推出的创新性的大数据处理产品,除却读写性能、存储压缩能力强大之外,还有安装简单、操作难......
  • JUC学习笔记——共享模型之不可变
    JUC学习笔记——共享模型之不可变在本系列内容中我们会对JUC做一个系统的学习,本片将会介绍JUC的不可变内容我们会分为以下几部分进行介绍:不可变案例不可变设计模式之......
  • C++ 内存分区模型
    代码区:存放函数的二进制代码,由操作系统管理全局区:存放全局变量、静态变量以及常量。栈区:由编译器自动分配释放,存放函数的参数值,局部变量等堆区:由程序员分配和释放,若......
  • Confluent.Kafka Kafka部署安装及简单使用
    Kafka部署安装及简单使用 一、环境准备1、jdk8+2、zookeeper 3、kafka说明:在kafka较新版本中已经集成了zookeeper,所以不用单独安装zookeeper,只需要在kafka文件......
  • K8s部署owncloud
    目录owncloudhelminitowncloudhelpdebugconfigowncloudhttps://hub.kubeapps.com/charts/bitnami/owncloudhelminitownclouddockerpulldocker.io/bitnami/ow......
  • Java 内存模型及若干相关问题
    java的内存模型的理解java的内存模型是一种抽象,对java语言在不同硬件平台上运行的差异的一种抽象描述,目的是屏蔽不同硬件平台之间的差异。JMM定义了线程和主存之间的访......
  • Prism通过反射机制自动注册对话视图模型
    摘要说明在使用WPF+Prism开发中,有时会需要使用到一些弹窗服务,而在Prism当中,我们使用Dialog是需要注入到IOC容器当中的,传统的写法如下:而当Dialog过多时或者需要新增一个......
  • Kubernetes部署ldap
    目录docldapinitpvldapinituse查看状态dochttps://hub.kubeapps.com/charts/geek-cookbook/openldapldap389tcp636tcpinitpvkubectlapply-f/free_cicd......