C 語言版 ORT 入門

目錄

構建版本

產物 描述 支援的平臺
Microsoft.ML.OnnxRuntime CPU (釋出版) Windows, Linux, Mac, X64, X86 (僅限 Windows), ARM64 (僅限 Windows)…更多詳細資訊: 相容性
Microsoft.ML.OnnxRuntime.Gpu GPU - CUDA (釋出版) Windows, Linux, Mac, X64…更多詳細資訊: 相容性
Microsoft.ML.OnnxRuntime.DirectML GPU - DirectML (釋出版) Windows 10 1709+
onnxruntime CPU, GPU (開發版), CPU (裝置端訓練) 與釋出版相同
Microsoft.ML.OnnxRuntime.Training CPU 裝置端訓練 (釋出版) Windows, Linux, Mac, X64, X86 (僅限 Windows), ARM64 (僅限 Windows)…更多詳細資訊: 相容性

.zip 和 .tgz 檔案也作為資產包含在每個 Github 釋出版本中。

API 參考

參考 onnxruntime_c_api.h

  1. 包含 onnxruntime_c_api.h
  2. 呼叫 OrtCreateEnv
  3. 建立會話: OrtCreateSession(env, model_uri, nullptr,…)
    • 可選地新增更多執行提供程式 (例如,對於 CUDA 使用 OrtSessionOptionsAppendExecutionProvider_CUDA)
  4. 建立張量 1) OrtCreateMemoryInfo 2) OrtCreateTensorWithDataAsOrtValue
  5. OrtRun

功能

  • 從磁碟模型檔案和一組 SessionOptions 建立 InferenceSession。
  • 註冊自定義日誌記錄器。
  • 註冊自定義分配器。
  • 註冊預定義提供程式並設定優先順序順序。ONNXRuntime 有一組預定義的執行提供程式,如 CUDA、DNNL。使用者可以將其提供程式註冊到其 InferenceSession。註冊順序也表示偏好順序。
  • 使用輸入執行模型。這些輸入必須在 CPU 記憶體中,而不是 GPU。如果模型有多個輸出,使用者可以指定他們想要的輸出。
  • 將以 protobuf 格式編碼的記憶體中 ONNX 張量轉換為可用作模型輸入的指標。
  • 設定每個會話的執行緒池大小。
  • 設定每個會話的圖最佳化級別。
  • 動態載入自定義運算子。 說明
  • 能夠從位元組陣列載入模型。請參見 onnxruntime_c_api.h 中的 OrtCreateSessionFromArray
  • 全域性/共享執行緒池: 預設情況下,每個會話都會建立自己的執行緒池集合。在同一程序中需要建立多個會話(用於推斷不同的模型)的情況下,每個會話都會建立多個執行緒池。為了解決這種低效率問題,我們引入了一項名為全域性/共享執行緒池的新功能。其基本思想是在多個會話之間共享一組全域性執行緒池。此功能的典型用法如下:
    • 填充 ThreadingOptions。使用 0 值讓 ORT 選擇預設值。
    • 使用 CreateEnvWithGlobalThreadPools() 建立環境
    • 建立會話並對會話選項物件呼叫 DisablePerSessionThreads()
    • 照常呼叫 Run()
  • 在會話之間共享分配器
    • 描述: 此功能允許同一程序中的多個會話使用相同的分配器。
    • 場景: 在同一程序中您有多個會話,並且發現記憶體使用率很高。其中一個原因如下。每個會話都會建立自己的 CPU 分配器,預設情況下它是基於競技場(arena)的。 ORT 實現了一個簡化版的競技場分配器,該分配器基於 Doug Lea 的最佳匹配(best-first)合併演算法。每個分配器都存在於其自己的會話中。它在初始化時分配一大塊記憶體,然後根據分配/解除分配需求對這塊初始區域進行分塊、合併和擴充套件。隨著時間的推移,競技場最終會為每個會話留下未使用的記憶體塊。此外,競技場分配的記憶體從不返回給系統;一旦分配,它就始終保持分配狀態。當使用多個會話(每個會話都有自己的競技場)時,所有這些因素累加起來,從而增加了程序的整體記憶體消耗。因此,在會話之間共享競技場分配器變得很重要。
    • 用法:
      • 使用 CreateAndRegisterAllocator API 建立並向 env 註冊一個共享分配器。除非會話選擇透過將 session_state.use_env_allocators 設定為“0”來覆蓋此設定,否則使用相同 env 例項的所有會話都將重用此分配器。
      • 對於每個希望使用 env 註冊分配器的會話,將其 session.use_env_allocators 設定為“1”。
      • 有關示例,請參見 https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc 中的測試 TestSharedAllocatorUsingCreateAndRegisterAllocator
      • 配置 OrtArenaCfg (從 ORT 1.8 版本起,使用 API CreateArenaCfgV2 建立 OrtArenaCfg 例項;之前的版本使用現在已棄用的 CreateArenaCfg 來建立例項)
        • CreateArenaCfgV2 接受以下所述的鍵列表以及一組相應的值(每個鍵一個值)。這些配置的預設值可以在 BFCArena 類中找到。有關 CreateArenaCfgV2 的示例用法,請參見 https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc 中的測試 ConfigureCudaArenaAndDemonstrateMemoryArenaShrinkage
        • max_mem: 這是競技場分配的最大記憶體量。如果任何現有區域都無法滿足某個記憶體塊的需求,競技場會根據可用記憶體(max_mem - 已分配量)再分配一個區域來擴充套件自身。如果可用記憶體少於請求的擴充套件量,則返回錯誤。
        • arena_extend_strategy: 目前只能取 2 個值:kSameAsRequested 或 kNextPowerOfTwo。顧名思義,kNextPowerOfTwo(預設值)按 2 的冪次擴充套件競技場,而 kSameAsRequested 每次按與分配請求相同的大小進行擴充套件。kSameAsRequested 適用於更高階的配置,在這些配置中您提前知道預期的記憶體使用情況。
        • initial_chunk_size_bytes: 此配置僅在競技場擴充套件策略為 kNextPowerOfTwo 時才相關。這是競技場在首次分配時(如果首次記憶體請求大於此值,則分配大小將大於此提供值)分配的區域的(可能)大小。記憶體塊從該區域分配給請求。如果日誌顯示競技場的擴充套件量遠超預期,則最好為此選擇一個足夠大的初始大小。
        • initial_growth_chunk_size_bytes: 請在閱讀本節之前閱讀“記憶體競技場收縮”一節。此配置僅在競技場擴充套件策略為 kNextPowerOfTwo 時才相關。目前,此值是競技場收縮後首次分配的(可能)大小(競技場收縮後,如果記憶體請求大於此值,將導致更高的分配大小)。競技場(可能)的首次分配由 initial_chunk_size_bytes 定義,隨後的分配可能是 initial_chunk_size_bytes * 2initial_chunk_size_bytes * 4,依此類推。如果競技場收縮(即)解除分配任何這些記憶體區域,我們希望“重置”收縮後首次分配的大小。這是當前的定義。將來,此配置可能用於控制競技場的其他“以增長為中心”的行為(即)競技場在首次分配(初始塊)之後的第二次分配(競技場增長)可能由該引數定義。
        • max_dead_bytes_per_chunk: 這控制了是否拆分一個記憶體塊以滿足分配請求。目前,如果記憶體塊大小與請求大小之間的差值小於此值,則不會拆分該記憶體塊。這有可能透過在整個過程中保留記憶體塊的一部分未被使用(因此稱為死位元組)而浪費記憶體,從而增加記憶體使用量(直到此記憶體塊返回到競技場)。
  • 記憶體競技場收縮
    • 描述: 預設情況下,記憶體競技場不會收縮(將未使用的記憶體返回給系統)。此功能允許使用者以某種節奏“收縮”競技場。目前,唯一支援的節奏是在每次 Run() 結束時(即)如果使用此功能,則在每次 Run() 結束時掃描競技場記憶體以可能釋放未使用的記憶體。這透過 RunOption 實現。
    • 場景: 您有一個動態形狀模型,可能偶爾會處理需要大量記憶體分配的請求。由於競技場預設不釋放任何記憶體,因此作為處理此請求的一部分,競技場的這種“增長”會永遠保持下去。這是次優的,因為大多數其他請求可能不需要那麼多記憶體(即)為了處理一兩個異常值而分配了過多的記憶體。如果這最能描述 ORT 的使用場景,那麼使用此收縮功能是一個選擇。此功能僅適用於相關記憶體分配器本身是基於競技場的分配器。
    • 用法: 有關示例,請參見 https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc 中的測試 ConfigureCudaArenaAndDemonstrateMemoryArenaShrinkage。為了最佳地使用此功能,需要根據用例適當地配置要收縮的記憶體競技場。請參閱上面如何使用 OrtArenaCfg 例項配置競技場分配器。此功能根據兩種可用的競技場擴充套件策略(kSameAsRequested 和 kNextPowerOfTwo)略有不同,如下所述:
      • kNextPowerOfTwo: 如果這是選定的配置,則除了初始分配之外的所有記憶體分配都將在收縮時考慮解除分配。其思想是,使用者設定足夠高的 initial_chunk_size_bytes 來處理大多數模型請求,而無需分配更多記憶體(即)此初始記憶體足以滿足任何平均請求。作為處理異常請求的一部分而分配的任何後續分配是唯一的解除分配候選者。
      • kSameAsRequested: 如果這是選定的配置,則所有記憶體分配都將在收縮時考慮解除分配。這是因為,目前 initial_chunk_size_bytes 與此策略不相關。
  • 從非競技場記憶體中為初始化器分配記憶體(適用於高階使用者)
    • 描述: 如果初始化器內容儲存的裝置所對應的分配器是基於競技場的分配器,並且希望防止因分配這些初始化器的記憶體而引起的任何(潛在的)過度競技場增長,那麼此功能提供了這種能力。
    • 場景: 您有一個相當簡單的模型,它在 Run() 期間本身不需要分配大量記憶體,但該模型具有相對大量的初始化器,以至於如果使用競技場分配這些初始化器的記憶體,則整個競技場已分配記憶體中的未使用的記憶體可能會遠遠超過模型在 Run() 期間實際所需的記憶體。在這種情況下,並且如果模型要部署在記憶體受限的環境中,使用此功能將很有意義,以防止競技場中因初始化器記憶體分配而引起的任何過度增長。使用此功能意味著競技場僅用於分配模型運算子所需的記憶體。似乎為競技場設定足夠高的初始塊大小 (initial_chunk_size_bytes) 以考慮初始化器和 Run() 期間所需的任何預期記憶體將避免出現問題。但這問題在於,某些 EP 內部使用按執行緒分配器,配置中設定的任何高初始塊大小都將應用於每個分配器,並導致記憶體浪費,因為最終只有一個按執行緒分配器分配初始化器的記憶體。
    • 用法: 有關示例,請參見 https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc 中的測試 AllocateInitializersFromNonArenaMemory
  • 在會話之間共享初始化器及其 ORT 預處理版本
    • 描述: 此功能允許使用者在多個會話之間共享初始化器(及其 ORT “預處理”版本)的相同例項。
    • 場景: 您有多個模型使用相同的初始化器集,除了模型的最後幾層,並且您在同一程序中載入這些模型。當每個模型(會話)建立相同初始化器的單獨例項時,會導致過度和浪費的記憶體使用,因為在這種情況下它是相同的初始化器。您希望最佳化記憶體使用,同時能夠靈活地分配初始化器(甚至可能將它們儲存在共享記憶體中)。
    • 用法: 在呼叫 CreateSession 之前,使用 AddInitializer API 將預分配的初始化器新增到會話選項中。使用會話選項的相同例項建立多個會話,從而允許在會話之間共享初始化器。請參見 C API 示例用法 (TestSharingOfInitializerAndItsPrepackedVersion)C# API 示例用法 (TestSharingOfInitializerAndItsPrepackedVersion)
    • 在某些 ORT 運算子實現中,模型載入時會預處理初始化器(此過程稱為“預打包”),以促進在某些平臺上進行最佳運算子推斷。預設情況下,這些初始化器的預處理版本是按會話維護的(即)它們不在會話之間共享。要啟用在會話之間共享這些版本,請建立一個容器(使用 CreatePrepackedWeightsContainer)並在會話建立時傳入,以便在會話之間共享共享初始化器的預打包版本,並且這些版本不會在記憶體中重複。上述 C 和 C# 中引用的相同測試也顯示了此功能的示例用法。注意:任何希望實現預打包的核心開發人員都必須編寫一個測試,該測試觸發使用核心可能預打包的所有權重的預打包,並且必須測試這些預打包權重在會話之間的共享。請參見 核心測試 (SharedPrepackedWeights)

部署

Windows 10

您的安裝程式應將 onnxruntime.dll 放在與您的應用程式相同的資料夾中。您的應用程式可以使用載入時動態連結執行時動態連結來繫結到該 dll。

這是一篇關於 Windows 如何查詢支援 dll 的重要文章:動態連結庫搜尋順序

在某些情況下,應用程式不是直接使用 onnxruntime,而是呼叫使用 onnxruntime 的 DLL。構建這些使用 onnxruntime 的 DLL 的人員需要注意資料夾結構。不要修改系統 %path% 變數來新增您的資料夾。這可能與機器上其他也使用 onnxruntime 的軟體發生衝突。相反,將您的 DLL 和 onnxruntime DLL 放在同一個資料夾中,並使用執行時動態連結明確繫結到該副本。您可以使用此示例在 GetModulePath() 中所做的程式碼來找出您的 dll 是從哪個資料夾載入的。

遙測

要在官方 Windows 版本上啟用/停用遙測收集,請在 C API 中使用 Enable/DisableTelemetryEvents()。有關遙測收集和 Microsoft 隱私政策的更多資訊,請參閱隱私頁面。

示例

請參見 Candy 風格遷移