iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0

前面介紹的nvinfer是用本地模型推論,而今天要介紹的nvinferserver則是使用Triton Inference Server(後續簡稱Triton Server)運行推論服務。為什麼是推論服務呢?因為Triton Server是一個模型託管服務,它可以集中管理模型,透過遠程調用(RPC)的方式執行推論請求,而模型的調度則是在伺服端內完成,客戶端不必處理調度的細節。

認識nvinferserver

這個元件其實跟nvinfer的功能完全相同,只是如同剛才所說的是透過遠程調用完成推論,不過因為它的設定檔跟系統配置方式截然不同,所以還是得單獨出來介紹。那我會以nvinfer介紹過的設定欄位來對照nvinferserver的設定欄位。

設定檔請參照/opt/nvidia/deepstream/deepstream/sources/apps/sample_apps/deepstream-test1/dstest1_pgie_nvinferserver_config.txt

因為nvinferserver這邊把設定群組分開許多,所以我會以這邊的每個群組去對照nvinfer的欄位,順序會不一樣。

infer_config群組

infer_config {
  unique_id: 1
  gpu_ids: [0]
  max_batch_size: 30
  [...]
}
nvinfer nvinferserver
gie-unique-id unique_id
batch-size max_batch_size

gpu_ids

這邊多了這一項是Triton Server特有的功能。因為推論任務抽象化,我們可以設定Triton Server使用多個GPU資源去執行推論任務,客戶端只管發請求,不必處理不同GPU之間的調度。

backend群組

backend {
  inputs: [ {
    name: "input_1:0"
  }]
  outputs: [
    {name: "output_cov/Sigmoid:0"},
    {name: "output_bbox/BiasAdd:0"}
  ]
  [...]
}

inputsoutputs

這個兩個是用來描述輸入和輸出tensor,官方文件的描述這兩項是Optional,當backend需要明確知道這些資訊時才要寫上去,就不多作介紹囉。

triton群組

triton {
  model_name: "Primary_Detector"
  version: -1
  [...]
}

model_name

模型是以固定的資料夾結構去區分,這個model_name就等於是資料夾名稱。

version

模型的版本號。模型主目錄下會再以數字做為資料夾名稱,放置各個版本的模型,例如version: 1就去主目錄底下的1資料夾找模型,而version: -1則是使用數字最大的那個資料夾。

model_repo群組

Triton Server有提供C-API模式,這個模式不用啟動Server,而是將建立in-memory的Server實例,所以所有的CUDA Memory都是在同一個進程內,效率幾乎等效於直接調用TensorRT模型。這個群組就是C-API模式需要的設定。

model_repo {
  root: "../../../../samples/triton_model_repo"
  strict_model_config: true
}

root

所有的模型都是以主目錄在往下分層,root就是那個主目錄。

strict_model_config

每個模型目錄底下都要放一個設定檔,預設的設定檔是config.pbtxt。這個屬性啟用的時,如果你有指定要用其他設定檔就要使用這一項,但通常預設的那一份就夠用了,而官方是建議設定為true就好。

preprocess群組

preprocess {
  network_format: MEDIA_FORMAT_NONE
  tensor_order: TENSOR_ORDER_LINEAR
  tensor_name: "input_1:0"
  maintain_aspect_ratio: 0
  frame_scaling_hw: FRAME_SCALING_HW_DEFAULT
  frame_scaling_filter: 1
  [...]
}
nvinfer nvinferserver
model-color-format network_format
network-input-order tensor_order
maintain-aspect-ratio maintain_aspect_ratio
scaling-compute-hw frame_scaling_hw
scaling-filter frame_scaling_filter

有幾項是nvinfer設定檔沒提到的,就在這邊進一步介紹

network_format

預設都是將影像以RGB格式轉為Tensor,但是有些模型訓練時是使用BGR格式,所以這個屬性可以設定

MEDIA_FORMAT_NONE
IMAGE_FORMAT_RGB
IMAGE_FORMAT_BGR
IMAGE_FORMAT_GRAY

至於為什麼跑出一個MEDIA_FORMAT_NONE,我也不知道,我猜是直接複製不管數據排列。

tensor_order

預設都是使用NCHW,但有些老一點的模型是用NHWC,當你有需求時就要改這個設定

TENSOR_ORDER_NONE
TENSOR_ORDER_LINEAR (NCHW)
TENSOR_ORDER_NHWC

TENSOR_ORDER_NONE的說明如下,老實說我也看得不是很懂。總之沒意外的話都還是直接設定TENSOR_ORDER_LINEAR

It can deduce the value from backend layers info if set to TENSOR_ORDER_NONE

tensor_name

當模型有多個輸入時,可以用這個欄位設定你要執行前處理的tensor。如果只有一個輸入,那麼這項可以忽略不設定。

frame_scaling_hw

模型的輸入都會給定一個固定尺寸,DeepStream的作法是先將影格縮放到跟輸入相同尺寸的影像,例如1280x720縮放到640x640,接著再將縮放後的影像轉換為Tensor。這裡就牽涉到縮放的運算是要在哪個硬體上完成,有以下這些選項

FRAME_SCALING_HW_DEFAULT
FRAME_SCALING_HW_GPU (Default for dGPU)
FRAME_SCALING_HW_VIC (Default for Jetson)

預設是選擇FRAME_SCALING_HW_DEFAULT,元件會根據平台切換到FRAME_SCALING_HW_GPUFRAME_SCALING_HW_VIC。GPU大家都可以理解,就是用CUDA運算,但VIC是什麼呢?

全名是Video and Image Compositor,還記不記得先前提到的硬體編碼/解碼器,VIC也是屬於為特定任務開發的硬體,專門負責影像處理。至於為什麼要有VIC這個硬體,大概是因為Jetson這種邊緣平台的GPU資源非常珍貴,而推論任務以NVIDIA的硬體來說也只能在GPU上運作,因此VIC的存在可以將影像處理的任務從GPU上卸載出來。

註記

VIC雖然可以處理影像縮放,但是根據我的開發經歷,使用上是有一些限制的

  • 不支援RGB或BGR這種3通道的影像處理,必須是RGBA或NV12
  • 縮放的係數有限制,太大的縮放係數API會回傳錯誤
  • 最小尺寸限制16x16

frame_scaling_filter

縮放算法。直接以經驗跟網路上的資料上結論:

  • NvBufSurfTransformInter_Nearest(0)快速但容易產生鋸齒
  • NvBufSurfTransformInter_Bilinear(1)慢一些但更平滑

normalize群組

normalize {
  scale_factor: 0.00392156862745098
  channel_offsets: [0, 0, 0]
}
nvinfer nvinferserver
net-scale-factor scale_factor
offsets channel_offsets

postprocess群組

postprocess {
  labelfile_path: "../../../../samples/models/Primary_Detector/labels.txt"
  [...]
}
nvinfer nvinferserver
labelfile-path labelfile_path

labelfile_path

將模型輸出的數值對照成文字的檔案,要按照DeepStream設計的形式去描述。有提供這份檔案的話,元件會自動幫你加在輸出的Metadata上。

detection群組

detection {
  num_detected_classes: 4
  per_class_params {
    key: 0
    value { pre_threshold: 0.4 }
  }
  nms {
    confidence_threshold:0.2
    topk:20
    iou_threshold:0.5
  }
}

這邊相較nvinfer,設定就分類的比較明確,總之你要用哪個就寫哪個,參數就從官方文件去搜尋。這部分參數比較多而且大同小異,就不多介紹了。

input_control群組

input_control {
  process_mode: PROCESS_MODE_FULL_FRAME
  operate_on_gie_id: -1
  interval: 0
}
nvinfer nvinferserver
process-mode process_mode
operate-on-gie-id operate_on_gie_id
interval interval

process_mode

  • PROCESS_MODE_FULL_FRAME對應到Primary模式
  • PROCESS_MODE_CLIP_OBJECTS對應到Secondary模式

grpc群組

範例的設定檔沒有,但必須要介紹,所以我們參考另外一個檔案/opt/nvidia/deepstream/deepstream/configs/deepstream-app-triton-grpc/config_infer_plan_engine_primary.txt

grpc {
  url: "localhost:8001"
  enable_cuda_buffer_sharing: true
}

Triton Server以獨立的進程啟動時,有提供HTTP和gRPC兩種遠程調用的接口,而gRPC的優勢在於序列化跟反序列化是二進制數據,性能優勢更高,串流應用會建議使用gRPC接口去調用

url

Triton Server的通訊位置,預設通訊埠是8001

enable_cuda_buffer_sharing

這項特別重要,只有Triton Server運行在同一個主機上時可以使用,也可以是同主機、不同容器。因為預設的行為是Client會將整個Tensor序列化後透過網路發送,到Server再返序列化後複製到CUDA Memory,一聽就知道這個調用方式會直接拖垮性能,不可能用在即時串流。

這個屬性就是讓模型使用CUDA Shared Memory作為Tensor的儲存空間,遠程調用時的訊息只傳遞記憶體的位置,因為是共享記憶體,所以Server收到時可以直接從這個位置去操作該記憶體,完全消除了複製的成本,性能也是逼近直接調用TensorRT模型。

結語

設定參數實在太多了,又是好長的一篇文章,希望可以幫助初次使用DeepStream的人來解少查詢這些設定用意的時間,畢竟我當時看到相同功能的元件還得分兩種設定文件看,屬實非常痛苦。跟nvinfer一樣,明天我們就單獨介紹Triton Server怎麼使用吧。


上一篇
[Day 09] TensorRT模型小幫手trtexec
下一篇
[Day 11] Triton Inference Server
系列文
深入認識DeepStream,不只是停在執行範例13
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言