[翻譯] NVIDIA HugeCTR,GPU 版本參數服務器 --(10)--- 推理架構

[翻譯] NVIDIA HugeCTR,GPU 版本參數服務器 --(10)--- 推理架構

0x00 摘要

經過9篇文章之後,我們基本把 HugeCTR 的訓練過程梳理了以下,現在我們有必要看看HugeCTR如何進行推理,這樣可以讓我們從整體上有一個更好的把握。而且我們之前都是分析分佈式訓練,此處恰好可以看看分佈式推理。

本文翻譯自 https://github.com/triton-inference-server/hugectr_backend/blob/main/docs/architecture.md。

HugeCTR Backend (https://github.com/triton-inference-server/hugectr_backend/)是一個 GPU 加速的推薦模型部署框架,旨在通過解耦參數服務器、嵌入緩存和模型權重來有效地使用 GPU 內存來加速推理。HugeCTR 後端通過使用在多個模型實例之間共享的嵌入緩存來支持跨多 GPU 的併發模型推理。

本系列其他文章如下:

[源碼解析] NVIDIA HugeCTR,GPU 版本參數服務器 --(1)

[源碼解析] NVIDIA HugeCTR,GPU版本參數服務器--- (2)

[源碼解析] NVIDIA HugeCTR,GPU版本參數服務器---(3)

[源碼解析] NVIDIA HugeCTR,GPU版本參數服務器--- (4)

[源碼解析] NVIDIA HugeCTR,GPU版本參數服務器--- (5) 嵌入式hash表

[源碼解析] NVIDIA HugeCTR,GPU版本參數服務器--- (6) --- Distributed hash表

[源碼解析] NVIDIA HugeCTR,GPU 版本參數服務器---(7) ---Distributed Hash之前向傳播

[源碼解析] NVIDIA HugeCTR,GPU 版本參數服務器---(8) ---Distributed Hash之後向傳播

[源碼解析] NVIDIA HugeCTR,GPU 版本參數服務器 --(9)--- Local hash表

0x01 設計

HugeCTR Backend採用分層框架,通過Parameter Server隔離嵌入表的加載,以此防止服務被部署在多個GPU上的多個模型影響,並通過嵌入緩存來實現高服務可用性。GPU緩存用於在推理過程中加速嵌入向量查找效率。

HugeCTR 後端還提供以下功能:

  • 併發模型執行:多個模型和同一模型的多個實例可以在同一 GPU 或多個 GPU 上同時運行。
  • 可擴展的後端:HugeCTR 提供的推理接口可以很容易地與後端 API 集成,這允許使用 Python 或 C++ 使用任何執行邏輯擴展模型。
  • 輕鬆部署新模型:更新模型應儘可能透明,不應影響推理性能。這意味着無論需要部署多少個模型,只要這些模型是使用 HugeCTR 訓練的,它們都可以通過相同的 HugeCTR 後端 API 加載。注意:在某些情況下,可能需要針對每個模型相應更新其配置文件。

0x02 HugeCTR後端框架

以下組件構成了 HugeCTR 後端框架:

  • 參數服務器負責加載和管理屬於不同模型的大型嵌入表。嵌入表爲嵌入緩存提供同步和更新服務。它還確保嵌入表完全加載並定期更新。
  • 嵌入式緩存可以直接加載到GPU內存之中。因此,它爲模型提供了嵌入向量查找功能,從而避免了從參數服務器傳輸數據(CPU 和 GPU 之間傳輸)時產生的相對較高的延遲。它還提供了更新機制,以及時加載最新緩存的嵌入向量,這樣確保了高命中率。
  • 模型比嵌入表小得多,因此它通常可以直接加載到GPU內存以加速推斷。該模型可以直接與 GPU 內存中的嵌入緩存交互以獲得嵌入向量。基於分層設計結構,多個模型實例將共享 GPU 內存中的嵌入緩存,以確保併發的模型執行。基於層級的依賴關係,嵌入表可以與模型的查找操作解耦,轉而依靠嵌入緩存實現高效低延遲的查找操作。這使得使用逐個接口初始化和依賴注入來實現推理邏輯成爲可能。

下面深入瞭解一下 HugeCTR Inference 接口的設計框架:

圖 1. HugeCTR 推理設計架構

在實際應用中,參數服務器用於加載所有模型的嵌入表。由於不同的模型在不同的應用場景下通過訓練會得到不同的嵌入表,因此在推理過程中會產生很高的內存開銷。通過引入Parameter Server,嵌入表可以在嵌入表規模較小的情況下直接加載到GPU內存中,如果GPU資源耗盡,則加載到CPU的內存中,當嵌入表尺寸太大時甚至會加載到固態硬盤(SSD)中) 。這確保了不同模型和這些模型之間共享的嵌入表是隔離的。

每個嵌入表將在不同的 GPU 上創建單獨的嵌入緩存。嵌入緩存將嵌入表視爲最小粒度,這意味着嵌入緩存可以直接查找並與相應的嵌入表同步。這種機制確保同一模型的多個模型實例可以在部署的 GPU 節點上共享相同的嵌入緩存。

0x03 GPU 嵌入緩存

3.1 啓用

當啓用 GPU 嵌入緩存機制時,模型將從 GPU 嵌入緩存中查找嵌入向量。如果嵌入向量在 GPU 嵌入緩存中不存在,它將返回默認嵌入向量。默認值爲 0。

HugeCTR 後端需要在 config.pbtxt 文件中設置以下參數:

parameters [
...
  {
 key: "gpucache"
 value: { string_value: "true" }
 },
 {
 key: "gpucacheper"
 value: { string_value: "0.5" }
 },
...
]
  • gpucache:使用此選項啓用 GPU 嵌入緩存機制。
  • gpucacheper:確定將從嵌入表加載到 GPU 嵌入緩存中的嵌入向量的百分比。默認值爲 0.5。因此,在上面的示例中,嵌入表的 50% 將被加載到 GPU 嵌入緩存中。
...
"inference": {
   "max_batchsize": 64,
   "hit_rate_threshold": 0.6,
   "dense_model_file": "/model/dcn/1/_dense_10000.model",
   "sparse_model_file": "/model/dcn/1/0_sparse_10000.model",
   "label": 1
 },

...
]
  • hit_rate_threshold:該選項根據命中率確定嵌入緩存和參數服務器的更新機制。如果嵌入向量查找的命中率低於設置的閾值,GPU 嵌入緩存將更新參數服務器上缺失的向量。GPU 嵌入緩存還會基於固定命中率來從參數服務器讀取嵌入向量進行更新。必須在模型推理配置 JSON 文件中設置命中率閾值。例如,請參閱dcn.jsondeepfm.json

3.2 禁用

當禁用 GPU 嵌入緩存機制(即"gpucache"設置爲false)時,模型將直接從參數服務器查找嵌入向量。在這種情況下,與 GPU 嵌入緩存相關的所有其他設置都將被忽略。

0x04 本地化部署

Parameter Server 可以在同一個節點和集羣上實現本地化部署,即每個節點只有一個 GPU,Parameter Server 部署在同一節點上。以下是 HugeCTR 支持的幾種部署場景:

  • 場景1:一個GPU(Node 1)部署一個模型,通過啓動多個並行實例來最大化embedding cache的命中率。

  • 場景2:一個GPU(Node 2)部署多個模型來最大化GPU資源,這需要在併發實例數量和多個嵌入緩存之間取得平衡,以確保有效使用 GPU 內存。每個嵌入緩存和參數服務器之間的數據傳輸使用一個獨立的 cuda 流。

    注意:在下面提到的示例中,在每個節點上部署了多個 GPU 和一個參數服務器。

  • 場景3:多個 GPU(Node 3)部署單個模型,在這種情況下,參數服務器可以幫助提高 GPU 之間嵌入緩存的命中率。

  • 場景4:多個GPU(Node 4)部署多個模型,這是本地化部署最複雜的場景,需要保證不同的embedding cache可以共享同一個Parameter Server,不同的model可以共享同一節點上的embedding cache。

圖 2 HugeCTR 推理本地化部署架構

0x05 具有分層 HugeCTR 參數服務器的分佈式部署

HugeCTR 引入分佈式Redis集羣作爲CPU緩存,用於存儲更大的嵌入表,並直接與GPU嵌入緩存交互。本地 RocksDB 作爲查詢引擎來支撐本地 SSD 上的完整嵌入表,以協助 Redis 集羣執行缺失的嵌入鍵查找。要啓用這種分層查找服務,您必須將"db_type"配置項添加到 ps.json 中"hierarchy"

{
    "supportlonglong": false,
    ...
    "db_type": "hierarchy",
    ...
    "models": [
      ...
    ]
}
  • 分佈式Redis集羣
    同步查詢:每個Model實例從本地化的GPU緩存中查找需要的embedding key,同時也會將缺失的embedding key(Keys not found in the GPU cache)存儲到缺失 keys buffer中。缺失 keys buffer與 Redis 實例同步交換,Redis 實例依次對任何丟失的嵌入鍵執行查找操作。從而,分佈式Redis集羣充當了二級緩存,這可以完全替代本地化參數服務器來加載所有模型的完整嵌入表。

    用戶只需要設置各個節點的ip和端口,即可在HugeCTR分層參數服務器之中啓用Redis集羣服務。但是Redis集羣作爲分佈式內存緩存,仍然受到每個節點CPU內存大小的限制。換句話說,所有模型的嵌入表的大小仍然不能超過集羣的總 CPU 內存。因此,用戶可以使用"cache_size_percentage_redis"來控制加載到Redis集羣中的模型嵌入表的大小。

    要利用具有 HugeCTR 的 Redis 集羣,需要添加以下配置選項以添加到 ps.json:

    {
      "supportlonglong": false,
      ...
      "db_type": "hierarchy",
      "redis_ip": "node1_ip:port,node2_ip:port,node3_ip:port,...",
      "cache_size_percentage_redis": "0.5",
      ...
      "models": [
        ...
      ]
    }
    
  • Localized RocksDB(Key-Value Store)
    對於超大規模的嵌入表,仍然無法完全加載到Redis集羣中,我們將在每個節點上啓用本地鍵值存儲(key-value)。

    RocksDB的同步查詢:Redis集羣客戶端在分佈式GPU緩存中查找embedding key時,會記錄丟失的embedding key(Keys not found in Redis cluster)並記錄到丟失key buffer中。丟失key buffer與本地 RocksDB 客戶端同步交換,然後將嘗試在本地 SSD 中查找這些密鑰。最終,SSD 查詢引擎將對所有模型缺失的嵌入鍵執行第三次查找操作。

    對於已經存儲在雲端的模型存儲庫(model repositories),RocksDB 將作爲本地 SSD 緩存,用於存儲 Redis 集羣無法加載的剩餘部分。因此,在實踐中,本地化的 RocksDB 實例充當了三級緩存。

    本地化的 RocksDB 的配置需要添加到 ps.json 中,如下圖:

    {
      "supportlonglong":false,
      ...
      "db_type":"hierarchy",
      "rocksdb_path":"/current_node/rocksdb_path",
      ...
      "models":[
        ...
      ]
    }
    

圖 3. HugeCTR 推理分佈式部署架構

0x06 Variant Compressed Sparse Row Input

(Variant Compressed Sparse Row (CSR) )數據格式通常用作 HugeCTR 模型的輸入。它允許高效地讀取數據,從原始數據中獲取數據語義信息,並避免花費太多時間進行數據解析。NVTabular 必須輸出相應的槽信息來指示分類數據的特徵文件。通過使用變體CSR數據格式,模型可以在從請求中讀取數據時獲取特徵字段信息。此外,也可以通過避免過多的請求數據處理來加快推理過程。對於每個樣本,有三種主要類型的輸入數據:

  • Dense Feature:代表實際的數值數據。
  • Column Indices:上游預處理工具 NVTabular 對分類數據執行 one-hot 和 multi-hot 編碼並將其轉換爲數值型數據。
  • Row ptr:包含每個插槽的分類特徵數。

圖 4. HugeCTR 推理 VCSR 輸入格式

VCSR 示例

每個模型的單個嵌入表

以上圖的第 0 行爲例。輸入數據包含四個槽,HugeCTR根據“Row ptr”輸入解析Row 0槽信息。所有嵌入向量都存儲在單個嵌入表中。

圖 5. 每個模型的單個嵌入表的 HugeCTR 推理 VCSR 示例

  • Slot 1:包含1 個分類特徵,嵌入鍵(embedding key) 爲 1。
  • Slot 2:包含1 個分類特徵,嵌入鍵爲 3。
  • Slot 3:包含0 個分類特徵。
  • Slot 4:包含2 個分類特徵,嵌入鍵爲 8 和 9。 HugeCTR 將從 GPU 的嵌入緩存或參數服務器中查找兩個嵌入向量,並最終得到一個用於 slot 4 的最終嵌入向量。

每個模型有多個嵌入表

同樣,我們以上圖中的Row 0爲例。然而,這次我們假設輸入數據由四個槽組成,其中前兩個槽(槽 1 和槽 2)屬於第一個嵌入表,後兩個槽(槽 3 和槽 4)屬於第二個嵌入表。所以需要兩個獨立的Row prts才能在輸入數據中形成完整的 Row prts

圖 6. 每個模型的多個嵌入表的 HugeCTR 推理 VCSR 示例

  • Slot 1:包含1個分類特徵,embedding key爲1,對應的embedding向量存儲在embedding table 1中。
  • Slot 2:包含1個分類特徵,embedding key爲3,對應的embedding向量存儲在embedding table 1中。
  • Slot 3:包含0 個分類特徵。
  • Slot 4:包含2個分類特徵,embedding key分別爲8和9。對應的embedding向量存儲在embedding table 2中。在這種情況下,HugeCTR會從GPU的embedding cache或者Parameter Server中查找兩個embedding vector並最終得到槽 4 的最終嵌入向量。

至此,HugeCTR 全部分析完畢,下一個系列我們來看看 TensorFlow 的分佈式訓練,敬請期待。

0xFF 參考

https://github.com/triton-inference-server/hugectr_backend/blob/main/docs/architecture.md

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章