自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Torchserve在轉(zhuǎn)轉(zhuǎn)GPU推理架構(gòu)中的實(shí)踐

開(kāi)發(fā) 前端
torchserve在轉(zhuǎn)轉(zhuǎn)GPU推理服務(wù)系統(tǒng)里的落地是一次平衡開(kāi)發(fā)效率與系統(tǒng)性能的工程實(shí)踐,總體上達(dá)到了計(jì)劃目標(biāo)并且取得了業(yè)務(wù)價(jià)值。

1 背景

轉(zhuǎn)轉(zhuǎn)面向二手電商業(yè)務(wù),在搜索推薦、智能質(zhì)檢、智能客服等場(chǎng)景落地了AI技術(shù)。在實(shí)踐的過(guò)程中,也發(fā)現(xiàn)了存在GPU執(zhí)行優(yōu)化不充分,浪費(fèi)計(jì)算資源,增加應(yīng)用成本等問(wèn)題。

此外還存在線上線下處理邏輯需要分別開(kāi)發(fā)的情況,造成額外的開(kāi)發(fā)成本和錯(cuò)誤排查成本,對(duì)一些需要高速迭代的業(yè)務(wù)場(chǎng)景的負(fù)面影響不可忽視。本文將會(huì)重點(diǎn)介紹基于Torchserve進(jìn)行推理服務(wù)部署架構(gòu)優(yōu)化的工程實(shí)踐,希望對(duì)面臨類似問(wèn)題的同學(xué)們有所幫助。

2 問(wèn)題和解決思路

2.1 現(xiàn)狀分析

圖片圖片

上圖為之前的推理系統(tǒng)架構(gòu)圖,采用CPU和GPU分離的架構(gòu)。這種架構(gòu)的特點(diǎn)是:

GPU部分和CPU部分解耦分別部署微服務(wù),預(yù)處理部分一般是在CPU上執(zhí)行,容易成為推理服務(wù)的性能瓶頸。解耦后可以將CPU部分部署在單獨(dú)的機(jī)器上,無(wú)限水平擴(kuò)容擴(kuò)容。

圖片圖片

上圖為美團(tuán)通用高效的推理服務(wù)部署架構(gòu)方案,可以看到架構(gòu)思路基本相同。

2.2 問(wèn)題

該方案具有很大的優(yōu)點(diǎn),也是業(yè)界多個(gè)公司采取的方案,但是架構(gòu)的選項(xiàng)也需要考慮具體的業(yè)務(wù)場(chǎng)景。該方案在轉(zhuǎn)轉(zhuǎn)的的場(chǎng)景里就出現(xiàn)了一些問(wèn)題,比如:

  • 迭代效率:GPU執(zhí)行部分的是基于torch或者tf的模型,可以接近0成本的部署到推理微服務(wù)上,但是CPU執(zhí)行部分包含一些預(yù)處理、后處理的部分,除了一些常見(jiàn)的圖像解碼、縮放、NMS等操作,還有很多自定義的邏輯,難以通過(guò)統(tǒng)一協(xié)議進(jìn)行低成本部署,需要在微服務(wù)里進(jìn)行二次開(kāi)發(fā),并且大部分情況下需要采用和離線算法實(shí)現(xiàn)不同的開(kāi)發(fā)語(yǔ)言,拖累業(yè)務(wù)迭代效率。當(dāng)前業(yè)界算法工程師的主要工作語(yǔ)言為python,對(duì)其他的語(yǔ)言或者dsl都存在一定的學(xué)習(xí)成本。
  • 網(wǎng)絡(luò)通信:轉(zhuǎn)轉(zhuǎn)的部分業(yè)務(wù)場(chǎng)景存在圖片尺寸較大的情況,因?yàn)槎值哪承┵|(zhì)檢場(chǎng)景需要高清圖片判斷有沒(méi)有破損、劃痕、污漬等細(xì)小痕跡。這樣微服務(wù)之間的網(wǎng)絡(luò)通信開(kāi)銷負(fù)擔(dān)比一般場(chǎng)景大很多。

2.3 解決思路

2.3.1框架調(diào)研

深度學(xué)習(xí)模型的常見(jiàn)的部署框架有以下幾個(gè):

特性

Triton

TorchServe

TensorFlow Serving

支持的框架

多種深度學(xué)習(xí)框架,包括 TensorFlow、PyTorch、ONNX、TensorRT、OpenVINO 等

專為 PyTorch 設(shè)計(jì),支持 PyTorch 模型

專為 TensorFlow 設(shè)計(jì),支持 TensorFlow 模型

性能

高性能推理服務(wù)器,支持動(dòng)態(tài)批處理、模型并行、多模型并發(fā)等

性能較好,支持多線程推理,GPU 支持良好

性能較好,支持多線程推理,GPU 支持良好

易用性

配置相對(duì)復(fù)雜,需要手動(dòng)配置模型倉(cāng)庫(kù)、推理服務(wù)等

易用性較好,提供了命令行工具和 Python API

易用性較好,提供了命令行工具和 gRPC/REST API

社區(qū)和支持

由 NVIDIA 開(kāi)發(fā)和維護(hù),社區(qū)活躍,文檔和示例豐富

由 Facebook 開(kāi)發(fā)和維護(hù),社區(qū)活躍,文檔和示例豐富

由 Google 開(kāi)發(fā)和維護(hù),社區(qū)非?;钴S,文檔和示例豐富

從性能和質(zhì)量的角度,三個(gè)框架水平都可以達(dá)到要求。重點(diǎn)考慮三個(gè)框架對(duì)于非深度學(xué)習(xí)部分的自定義邏輯支持:

  • tensoflow的tf.function裝飾器和AutoGraph機(jī)制 tf.function是TensorFlow 2.x中引入的一個(gè)重要特性,它通過(guò)在Python函數(shù)上應(yīng)用一個(gè)裝飾器,將原生Python代碼轉(zhuǎn)換為T(mén)ensorFlow圖代碼,從而享受圖執(zhí)行帶來(lái)的性能優(yōu)勢(shì)。AutoGraph是tf.function底層的一項(xiàng)關(guān)鍵技術(shù),它可以將復(fù)雜的Python代碼,比如包含while,for,if的控制流,轉(zhuǎn)換為T(mén)ensorFlow的圖,例如:
@tf.function
def fizzbuzz(n):
  for i in tf.range(n):
    if i % 3 == 0:
      tf.print('Fizz')
    elif i % 5 == 0:
      tf.print('Buzz')
    else:
      tf.print(i)

fizzbuzz(tf.constant(15))
  • triton Python Backend機(jī)制 triton允許使用Python編寫(xiě)后端邏輯,這樣可以利用Python的靈活性和豐富的庫(kù)。Python Backend通過(guò)實(shí)現(xiàn)initialize、execute和finalize等接口來(lái)完成模型的加載、推理和卸載。這種方式適合于需要復(fù)雜邏輯處理的場(chǎng)景,比如多模型協(xié)同工作或者需要自定義預(yù)處理和后處理的情況。Python Backend可以與Triton的pipeline功能結(jié)合,實(shí)現(xiàn)更復(fù)雜的推理流程。例如下面的代碼中,實(shí)現(xiàn)了一個(gè)initialize方法初始化,并且實(shí)現(xiàn)一個(gè)execute方法執(zhí)行具體的邏輯,代碼為python實(shí)現(xiàn)。
import numpy as np

class PythonAddModel:
    def initialize(self, args):
        self.model_config = args['model_config']

    def execute(self, requests):
        responses = []
        for request in requests:
            out_0 = request.inputs[0].as_numpy() + request.inputs[1].as_numpy()
            out_tensor_0 = pb_utils.Tensor("OUT0", out_0.astype(np.float32))
            responses.append(pb_utils.InferenceResponse([out_tensor_0]))
        return responses
  • torchserve Custom handlers TorchServe通過(guò)定義handler來(lái)處理模型的加載、預(yù)處理、推理和后處理。handler通常繼承自BaseHandler類,并重寫(xiě)initialize、preprocess、inference和postprocess等方法。如下面代碼所示,與Triton Python Backend有些類似。
from ts.torch_handler import TorchHandler

class ImageClassifierHandler(TorchHandler):
    def initialize(self, params):
        """初始化模型"""
        self.model = SimpleCNN()
        self.model.load_state_dict(torch.load('model.pth', map_location=torch.device('cuda:0')))
        self.model.eval()

    def preprocess(self, batch):
        """預(yù)處理輸入數(shù)據(jù)"""
        images = [img.convert('RGB') for img in batch]
        images = [img.resize((224, 224)) for img in images]
        images = [torch.tensor(np.array(img)).permute(2, 0, 1).float() for img in images]
        images = [img / 255.0 for img in images]
        return images

    def postprocess(self, outputs):
        """后處理輸出結(jié)果"""
        _, predicted = torch.max(outputs, 1)
        return predicted

2.3.2框架選型

tensorflow serving的tf.function裝飾器和AutoGraph機(jī)制并不能保證兼容所有的python代碼和控制流,并不滿足需求,在兼容第三方python包上也存在問(wèn)題。此外tensorflow作為早年應(yīng)用最廣的深度學(xué)習(xí)框架,近年來(lái)在流行度上已經(jīng)有被后來(lái)追上的趨勢(shì),tensorflow serving基本上只支持tensorflow框架,所以第一個(gè)排除。 

Triton Python Backend和torchserve Custom handlers在功能和機(jī)制上比較類似。都提供了一個(gè)靈活、易用且可擴(kuò)展的解決方案,特別適合于需要快速部署和靈活處理模型的場(chǎng)景??蚣芗嫒萆蟭riton支持主流的所有框架,torchserve主要支持pytorch和onnx協(xié)議,都可以滿足轉(zhuǎn)轉(zhuǎn)的需求。經(jīng)過(guò)調(diào)研和試用,我們最終選擇了torchserve作為本次的框架選項(xiàng),原因如下:

  • torchserve與PyTorch生態(tài)深度集成,而Triton的學(xué)習(xí)曲線相對(duì)陡峭。torchserve主要支持torch框架,同時(shí)只兼容onnx協(xié)議。在輕量級(jí)和易用性上更符合轉(zhuǎn)轉(zhuǎn)當(dāng)前的業(yè)務(wù)場(chǎng)景要求。例如在模型部署的格式轉(zhuǎn)換和配置上,torchserve相較于triton要簡(jiǎn)易很多。
  • 從后續(xù)轉(zhuǎn)轉(zhuǎn)GPU推理服務(wù)的演進(jìn)來(lái)看,長(zhǎng)期來(lái)看支持所有主流推理框架是必需的,短期在業(yè)務(wù)高速成長(zhǎng)期優(yōu)先選擇一個(gè)框架與長(zhǎng)期支持所有主流并不沖突。

3 torchserve實(shí)踐過(guò)程

3.1 torchserve使用與調(diào)優(yōu)

3.1.1 使用流程

圖片圖片

以一個(gè)圖像模型簡(jiǎn)單舉例,如圖所示:

  • 將模型權(quán)重文件及前后處理邏輯python代碼打包成一個(gè)mar包
  • mar包提交到torchserve進(jìn)程中進(jìn)行模型注冊(cè)
  • 請(qǐng)求到來(lái)后執(zhí)行圖片下載和模型前處理、推理、后處理,返回結(jié)果

mar包打包指令:

torch-model-archiver --model-name your_model_name --version 1.0 --serialized-file path_to_your_model.pth --handler custom_handler.py --extra-files path_to_any_extra_files
  • your_model_name:你為模型指定的名稱。
  • 1.0:模型的版本號(hào),可以根據(jù)實(shí)際情況進(jìn)行修改。
  • path_to_your_model.pth:你的 PyTorch 模型文件的路徑。
  • custom_handler.py:處理模型輸入和輸出的自定義處理函數(shù)文件。
  • path_to_any_extra_files:如果有其他需要一起打包的文件,可以在這里指定路徑,可以是多個(gè)文件路徑用逗號(hào)分隔。

torchserve的custom handler機(jī)制和易用性對(duì)于開(kāi)發(fā)效率的提升是顯著的,在我們的內(nèi)部場(chǎng)景里,一個(gè)單人維護(hù)的推理服務(wù),在半年內(nèi)節(jié)省了約32PD(人日)的開(kāi)發(fā)成本。

3.1.2 torch-trt

模型的主干網(wǎng)絡(luò)部分,需要進(jìn)行優(yōu)化,否則執(zhí)行效率差耗時(shí)較長(zhǎng)。torch-trt允許將PyTorch 模型轉(zhuǎn)換為 TensorRT 格式,從而能夠利用 TensorRT 強(qiáng)大的優(yōu)化引擎。TensorRT 針對(duì) NVIDIA GPU 進(jìn)行了高度優(yōu)化,能夠?qū)崿F(xiàn)快速的推理性能。它通過(guò)對(duì)模型進(jìn)行層融合、內(nèi)核自動(dòng)調(diào)整和內(nèi)存優(yōu)化等操作,顯著提高了模型的推理速度。

import torch
   import torch_tensorrt

   # Load your PyTorch model
   model = torch.load('path_to_your_model.pth')

   # Convert the model to TensorRT
   trt_model = torch_tensorrt.compile(model, inputs=[torch_tensorrt.Input((1, 3, 224, 224))], enabled_precisinotallow={torch.float32})

   # Save the converted model
   torch.save(trt_model, 'path_to_trt_model.pth')

torch-trt比起tensorflow-trt和triton-trt相對(duì)來(lái)說(shuō)比較簡(jiǎn)單:

  • 使用torch.compile可以一鍵轉(zhuǎn)換。
  • 整個(gè)流程用python用簡(jiǎn)單的代碼實(shí)現(xiàn),學(xué)習(xí)成本較低。
  • 與pytorch和torchserve無(wú)縫銜接。

圖片圖片

如上圖所示為torch-trt的優(yōu)化流程:

  • Partition Graph(劃分圖) 首先要對(duì) PyTorch 模型的計(jì)算圖進(jìn)行分析,找出其中 TensorRT 所支持的節(jié)點(diǎn)。這是因?yàn)椴⒎撬械?PyTorch 操作都能直接被 TensorRT 處理,需要確定哪些部分可以利用 TensorRT 的優(yōu)化能力。根據(jù)識(shí)別出的支持節(jié)點(diǎn)情況,決定哪些部分在 PyTorch 中運(yùn)行,哪些部分可以在 TensorRT 中運(yùn)行。對(duì)于可以在 TensorRT 中運(yùn)行的部分,將進(jìn)行后續(xù)的轉(zhuǎn)換操作。
  • Compile TensorRT(編譯 TensorRT) 對(duì)于在 Partition Graph 步驟中確定可以由 TensorRT 處理的節(jié)點(diǎn),將其轉(zhuǎn)換為 TensorRT 格式。這一步驟會(huì)利用 TensorRT 的優(yōu)化技術(shù),如層融合、內(nèi)核自動(dòng)調(diào)整和內(nèi)存優(yōu)化等,將這些節(jié)點(diǎn)轉(zhuǎn)換為高效的 TensorRT Engine(引擎),從而提高模型的推理速度。

分組

GPU利用率

CPU利用率

QPS

顯存占用

torch-base

40% ~ 80%

20%~40%

10

2GB

torch-trt

10% ~ 50%

100%

17

680MB

加入torch-trt之后的優(yōu)化效果如上面表格,可以看出:

  • trt優(yōu)化后,吞吐獲得了提升,符合預(yù)期,吞吐的提升主要是半精度和執(zhí)行流程優(yōu)化帶來(lái)的。顯存占用也因?yàn)榘刖群退阕尤诤洗蠓陆担项A(yù)期。
  • trt組的GPU沒(méi)有打滿,但是CPU打滿了,吞吐的瓶頸從GPU轉(zhuǎn)移到CPU,經(jīng)過(guò)排查原因是預(yù)處理和后處理部分的CPU操作在請(qǐng)求量大的時(shí)候已經(jīng)將CPU打滿了。這個(gè)問(wèn)題過(guò)去是通過(guò)CPU微服務(wù)水平擴(kuò)容解決的,在torchserve中CPU和GPU的執(zhí)行在一個(gè)進(jìn)程內(nèi),無(wú)法水平擴(kuò)容,下面將介紹解決方案。

3.2 預(yù)處理和后處理部分優(yōu)化

排查CPU執(zhí)行部分占用率較高的邏輯,原因?yàn)椴糠钟?jì)算密集型邏輯被放在了前后處理中,例如opencv庫(kù)中的一些api執(zhí)行和通過(guò)numpy、pandas等庫(kù)進(jìn)行矩陣計(jì)算。解決思路是將原來(lái)的python替換成NVIDIA官方提供的一些列對(duì)應(yīng)的cuda版本庫(kù)。例如cvCuda和cuDF分別對(duì)應(yīng)OpenCV與pandas,并且提供了相同的api,只需要在import包的時(shí)候進(jìn)行替換,開(kāi)發(fā)成本較低。

import cv2
import numpy as np
import cv2.cuda as cvcuda

# 讀取圖像
img = cv2.imread('your_image.jpg')

# 將圖像轉(zhuǎn)換為 GPU 上的格式
gpu_img = cvcuda.GpuMat(img)

# 使用 cvCuda 進(jìn)行高斯模糊
gaussian_filter = cvcuda.createGaussianFilter(gpu_img.type(), -1, (5, 5), 1.5)
blurred_gpu = gaussian_filter.apply(gpu_img)

# 將處理后的圖像轉(zhuǎn)換回 CPU 格式
blurred_img = blurred_gpu.download()

# 顯示結(jié)果
cv2.imshow('Original Image', img)
cv2.imshow('Blurred Image (cvCuda)', blurred_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

以上demo為例,只需要將cv2庫(kù)替換為cvCuda庫(kù)即可。此外計(jì)算密集型邏輯在CPU上執(zhí)行性價(jià)比并不高,很多時(shí)候是使用習(xí)慣所致,在深度學(xué)習(xí)時(shí)代之前OpenCV和pandas就比較流行了,后續(xù)沿用之前的用法。從下面NVIDIA官方提供的測(cè)試結(jié)果來(lái)看,相關(guān)計(jì)算邏輯在GPU上執(zhí)行可以獲得極大的性能提升。

圖片圖片

上圖為OpenCV和CV-CUDA在不同算子上的吞吐表現(xiàn)對(duì)比。 

下圖展示了在同一個(gè)計(jì)算節(jié)點(diǎn)上(2x Intel Xeon Platinum 8168 CPUs , 1x NVIDIA A100 GPU),以 30fps 的幀率處理 1080p 視頻,采用不同的 CV 庫(kù)所能支持的最大的并行流數(shù)

圖片圖片

下表為我們內(nèi)部的測(cè)試結(jié)果:

分組

GPU利用率

CPU利用率

QPS

顯存占用

torch-base

40% ~ 80%

20%~40%

10

2GB

torch-trt

10% ~ 50%

100%

17

680MB

GPU預(yù)處理+trt

60% ~ 80%

60%

40

2.1GB

從中可以看出,將預(yù)處理中計(jì)算密集型部分放在GPU上成功解決了此前遇到的問(wèn)題。吞吐比base提升了4倍,GPU占用率提升顯著,CPU占用率沒(méi)有打滿。需要注意的是顯存占用率相應(yīng)也會(huì)提升,因?yàn)橹霸趦?nèi)存中進(jìn)行的操作被移到了顯存上進(jìn)行。

3.3 Torchserve on Kubernetes

torchserve官方通過(guò)Helm Charts提供了一個(gè)輕量級(jí)的k8s部署方案,可以實(shí)現(xiàn)服務(wù)的可靠運(yùn)行和高可用性,,這也是我們?cè)诳蚣苓x型中看中torchserve的一個(gè)優(yōu)勢(shì)。

kubectl get pods

NAME                                             READY   STATUS    RESTARTS   AGE
grafana-cbd8775fd-6f8l5                          1/1     Running   0          4h12m
model-store-pod                                  1/1     Running   0          4h35m
prometheus-alertmanager-776df7bfb5-hpsp4         2/2     Running   0          4h42m
prometheus-kube-state-metrics-6df5d44568-zkcm2   1/1     Running   0          4h42m
prometheus-node-exporter-fvsd6                   1/1     Running   0          4h42m
prometheus-node-exporter-tmfh8                   1/1     Running   0          4h42m
prometheus-pushgateway-85948997f7-4s4bj          1/1     Running   0          4h42m
prometheus-server-f8677599b-xmjbt                2/2     Running   0          4h42m
torchserve-7d468f9894-fvmpj                      1/1     Running   0          4h33m

以上為一個(gè)集群的pods列表,除了torchserve的微服務(wù)階段,還提供了model-store功能,以及基于prometheus、grafana的監(jiān)控報(bào)警體系。再加上k8s原有的能力,既可實(shí)現(xiàn)一個(gè)輕量級(jí)的支持故障自動(dòng)恢復(fù)、負(fù)載均衡、滾動(dòng)更新、模型管理、安全配置的高可用性和可彈性擴(kuò)展系統(tǒng)。

4  后續(xù)工作

torchserve在轉(zhuǎn)轉(zhuǎn)GPU推理服務(wù)系統(tǒng)里的落地是一次平衡開(kāi)發(fā)效率與系統(tǒng)性能的工程實(shí)踐,總體上達(dá)到了計(jì)劃目標(biāo)并且取得了業(yè)務(wù)價(jià)值。但是也存在一些不足,比如說(shuō)原計(jì)劃前后處理部分線上和線下完全一致,共用相同的python代碼,但是實(shí)踐中遇到了CPU被打滿的情況改變了方案。盡管替代方案開(kāi)發(fā)成本較低但是仍然做不到Write once, run anywhere。

此外,當(dāng)前提供的解決方案以效率為先,兼顧性能,適合快速落地及迭代。后續(xù)計(jì)劃針對(duì)更復(fù)雜的業(yè)務(wù)場(chǎng)景(多模型推理等)及推理模型(llm推理等),提供進(jìn)階的解決方案。同時(shí),在云原生平臺(tái)建設(shè)上,當(dāng)前只是實(shí)現(xiàn)了一個(gè)入門(mén)版本,需要補(bǔ)課的內(nèi)容還很多。


關(guān)于作者

楊訓(xùn)政,轉(zhuǎn)轉(zhuǎn)算法工程方向架構(gòu)師,負(fù)責(zé)搜索推薦、圖像、大模型等方向的算法工程架構(gòu)工作。

責(zé)任編輯:武曉燕 來(lái)源: 轉(zhuǎn)轉(zhuǎn)技術(shù)
相關(guān)推薦

2022-10-28 08:31:43

2023-03-22 08:32:35

2022-10-28 09:15:02

2023-04-19 13:18:41

動(dòng)態(tài)線程池平臺(tái)

2023-06-07 08:32:32

引擎技術(shù)while

2023-08-24 08:11:39

斷路器監(jiān)控報(bào)警

2024-09-11 19:36:24

2024-09-19 22:22:41

多任務(wù)學(xué)習(xí)

2023-11-01 07:44:29

轉(zhuǎn)轉(zhuǎn)Flutter業(yè)務(wù)

2023-12-27 19:12:42

OLAP自助分析

2022-11-07 14:45:26

轉(zhuǎn)轉(zhuǎn)價(jià)格DDD

2023-03-02 08:54:32

2023-03-02 08:32:41

2023-07-12 08:33:34

引擎LiteFlow編排

2023-07-31 13:49:11

2023-02-08 09:42:30

策略方式容量

2022-12-15 08:35:01

用戶畫(huà)像平臺(tái)

2023-09-14 08:34:28

linux架構(gòu)參數(shù)

2024-06-06 08:18:42

回收業(yè)務(wù)

2024-08-08 07:13:36

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)