开始使用 ORT for C
目录
构建版本
工件 | 描述 | 支持的平台 |
---|---|---|
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。
- 调用 OrtCreateEnv
- 创建会话:OrtCreateSession(env, model_uri, nullptr,…)
- 可选地添加更多执行提供程序(例如,对于 CUDA,使用 OrtSessionOptionsAppendExecutionProvider_CUDA)
- 创建张量 1) OrtCreateMemoryInfo 2) OrtCreateTensorWithDataAsOrtValue
- OrtRun
功能特性
- 从磁盘模型文件和一组 SessionOptions 创建 InferenceSession。
- 注册自定义记录器。
- 注册自定义分配器。
- 注册预定义的提供程序并设置优先级顺序。ONNXRuntime 有一组预定义的执行提供程序,例如 CUDA、DNNL。用户可以将提供程序注册到他们的 InferenceSession。注册顺序也表示优先级顺序。
- 使用输入运行模型。这些输入必须在 CPU 内存中,而不是 GPU 内存中。如果模型有多个输出,用户可以指定他们想要的输出。
- 将以 protobuf 格式编码的内存中 ONNX 张量转换为可用作模型输入的指针。
- 设置每个会话的线程池大小。
- 设置每个会话的图优化级别。
- 动态加载自定义运算符。 说明
- 能够从字节数组加载模型。请参阅
OrtCreateSessionFromArray
在 onnxruntime_c_api.h。 - 全局/共享线程池: 默认情况下,每个会话都会创建自己的一组线程池。在需要在同一进程中创建多个会话(以推理不同的模型)的情况下,最终每个会话都会创建多个线程池。为了解决这种低效率问题,我们引入了一项名为全局/共享线程池的新功能。这里的基本思想是在多个会话之间共享一组全局线程池。此功能的典型用法如下
- 填充
ThreadingOptions
。使用值 0 让 ORT 选择默认值。 - 使用
CreateEnvWithGlobalThreadPools()
创建 env - 创建会话并在会话选项对象上调用
DisablePerSessionThreads()
- 像往常一样调用
Run()
- 填充
- 在会话之间共享分配器
- 描述:此功能允许多个会话在同一进程中使用相同的分配器。
- 场景:您在同一进程中有多个会话,并且看到内存使用率很高。其中一个原因如下。每个会话都创建自己的 CPU 分配器,默认情况下是基于 arena 的。 ORT 实现了 arena 分配器的简化版本,该版本基于 Doug Lea 的最佳优先合并算法。每个分配器都存在于自己的会话中。它在初始化时分配一大片内存区域,然后根据分配/释放需求对该初始区域进行分块、合并和扩展。随着时间的推移,arena 最终会在每个会话中留下未使用的内存块。此外,arena 分配的内存永远不会返回给系统;一旦分配,它将始终保持分配状态。当使用多个会话(每个会话都有自己的 arena)时,所有这些因素都会累加起来,从而增加进程的总体内存消耗。因此,在会话之间共享 arena 分配器变得非常重要。
- 用法:
- 使用
CreateAndRegisterAllocator
API 创建共享分配器并在 env 中注册。然后,所有使用同一 env 实例的会话都会重用此分配器,除非会话选择通过将session_state.use_env_allocators
设置为“0”来覆盖它。 - 对于每个想要使用 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
:这是 arena 分配的最大内存量。如果现有区域无法处理某个块,则 arena 会根据可用内存(max_mem - 已分配内存)分配一个额外的区域来扩展自身。如果可用内存小于请求的扩展量,则会返回错误。arena_extend_strategy
:目前只能取 2 个值:kSameAsRequested 或 kNextPowerOfTwo。顾名思义,kNextPowerOfTwo(默认值)将 arena 扩展 2 的幂次方,而 kSameAsRequested 每次扩展的大小与分配请求的大小相同。kSameAsRequested 适用于更高级的配置,在这些配置中,您预先知道预期的内存使用量。initial_chunk_size_bytes
:此配置仅在 arena 扩展策略为 kNextPowerOfTwo 时相关。这是 arena 在首次分配中分配的区域的(可能)大小(如果首次内存请求大于此值,则分配大小将大于此提供的值)。块从该区域移交给分配请求。如果日志显示 arena 扩展得比预期多得多,那么最好为此选择足够大的初始大小。initial_growth_chunk_size_bytes
:在阅读本节之前,请先阅读内存 arena 收缩部分。此配置仅在 arena 扩展策略为 kNextPowerOfTwo 时相关。目前,此值是 arena 收缩后首次分配的(可能)大小(arena 收缩后大于此值的内存请求将导致更大的分配大小)。arena 的(可能)首次分配由initial_chunk_size_bytes
定义,可能的后续分配为initial_chunk_size_bytes * 2
、initial_chunk_size_bytes * 4
等等。如果 arena 要收缩(即)释放这些内存区域中的任何一个,我们希望“重置”收缩后首次分配的大小。这是当前的定义。将来,此配置可能用于控制 arena 的其他“以增长为中心”的操作(即)arena 在首次分配(初始块)后进行的第二次分配(arena 增长)可以通过此参数定义。max_dead_bytes_per_chunk
:这控制是否拆分块以服务分配请求。目前,如果块大小和请求大小之间的差异小于此值,则不会拆分块。这有可能浪费内存,因为在整个过程中,块的一部分保持未使用状态(因此称为死字节),从而增加内存使用率(直到此块返回到 arena)。
- 使用
- 内存 arena 收缩
- 描述:默认情况下,内存 arena 不会收缩(将未使用的内存返回给系统)。此功能允许用户以一定的节奏“收缩” arena。目前,唯一支持的节奏是在每次 Run() 结束时(即)如果使用此功能,则会在每次 Run() 结束时扫描 arena 内存,以潜在地释放未使用的内存。这是通过 RunOption 实现的。
- 场景:您有一个动态形状模型,该模型可能偶尔会处理可能需要分配大量内存的请求。由于默认情况下 arena 不会释放任何内存,因此作为处理此请求一部分的 arena 的“增长”将永远保持下去。这是次优的,因为大多数其他请求可能不需要那么多内存(即)最终分配了太多内存只是为了处理一两个异常值。如果这最能描述 ORT 的使用场景,则可以使用此收缩功能。此功能仅在相关的内存分配器首先是基于 arena 的分配器时才适用。
- 用法:有关示例,请参阅 https://github.com/microsoft/onnxruntime/blob/main/onnxruntime/test/shared_lib/test_inference.cc 中的测试
ConfigureCudaArenaAndDemonstrateMemoryArenaShrinkage
。为了最佳地使用此功能,需要为用例适当地配置要收缩的内存 arena。请参阅上面如何使用OrtArenaCfg
实例配置 arena 分配器。此功能略微根据下面描述的两种可用的 arena 扩展策略(kSameAsRequested 和 kNextPowerOfTwo)进行了调整kNextPowerOfTwo
:如果这是选择的配置,则在收缩时,除了初始分配之外的所有内存分配都将被考虑用于释放。其思想是用户设置足够高的initial_chunk_size_bytes
以处理大多数模型请求,而无需分配更多内存(即)此初始内存足以服务任何平均请求。作为处理异常值请求的一部分分配的任何后续分配都是释放的唯一候选对象。kSameAsRequested
如果这是选择的配置,则在收缩时,所有内存分配都将被考虑用于释放。这是因为,目前,initial_chunk_size_bytes
与此策略无关。
- 从非 arena 内存为初始化器分配内存(供高级用户使用)
- 描述:如果与要存储初始化器内容的设备相关的分配器是基于 arena 的分配器,并且有人希望防止因为这些初始化器分配内存而引起的任何(潜在的)过度 arena 增长,则此功能提供了这种能力。
- 场景:您有一个相当简单的模型,该模型本身在 Run() 期间不需要分配大量内存,但是该模型具有相对大量的初始化器,因此,如果使用 arena 分配这些初始化器的内存,则总体 arena 分配内存中的未使用内存可能会远远超过模型在 Run() 期间实际需要的内存。在这种情况下,如果模型要部署在内存受限的环境中,则使用此功能将是有意义的,以便防止 arena 中因初始化器内存分配而引起的任何过度增长。使用此功能意味着 arena 仅用于分配模型运算符所需的内存。似乎为 arena 设置足够高的初始块大小 (
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% 变量来添加您的文件夹。这可能会与机器上也在使用 onnxruntme 的其他软件冲突。相反,请将您的 DLL 和 onnxruntime DLL 放在同一文件夹中,并使用运行时动态链接显式绑定到该副本。您可以使用像此示例在 GetModulePath() 中所做的代码来找出您的 dll 从哪个文件夹加载。
遥测
要在官方 Windows 版本上启用/禁用遥测收集,请使用 C API 中的 Enable/DisableTelemetryEvents()。有关遥测收集和 Microsoft 隐私政策的更多信息,请参阅 隐私 页面。