- Creating an InferenceSession from an on-disk model file and a set of SessionOptions.
- Registering customized loggers.
- Registering customized allocators.
- Registering predefined providers and set the priority order. ONNXRuntime has a set of predefined execution providers, like CUDA, DNNL. User can register providers to their InferenceSession. The order of registration indicates the preference order as well.
- Running a model with inputs. These inputs must be in CPU memory, not GPU. If the model has multiple outputs, user can specify which outputs they want.
- Converting an in-memory ONNX Tensor encoded in protobuf format to a pointer that can be used as model input.
- Setting the thread pool size for each session.
- Setting graph optimization level for each session.
- Dynamically loading custom ops. Instructions
- Ability to load a model from a byte array. See
- Global/shared threadpools: By default each session creates its own set of threadpools. In situations where multiple sessions need to be created (to infer different models) in the same process, you end up with several threadpools created by each session. In order to address this inefficiency we introduce a new feature called global/shared threadpools. The basic idea here is to share a set of global threadpools across multiple sessions. Typical usage of this feature is as follows
ThreadingOptions. Use the value of 0 for ORT to pick the defaults.
- Create env using
- Create session and call
DisablePerSessionThreads()on the session options object
- Share allocator(s) between sessions:
- Description: This feature allows multiple sessions in the same process to use the same allocator(s).
- Scenario: You’ve several sessions in the same process and see high memory usage. One of the reasons for this is as follows. Each session creates its own CPU allocator which is arena based by default. ORT implements a simplified version of an arena allocator that is based on Doug Lea’s best-first with coalescing algorithm. Each allocator lives in its own session. It allocates a large region of memory during init time and thereafter it chunks, coalesces and extends this initial region as per allocation/deallocation demands. Overtime the arena ends up with unused chunks of memory per session. Moreover, the memory allocated by the arena is never returned to the system; once allocated it always remains allocated. All these factors add up when using multiple sessions (each with its own arena) thereby increasing the overall memory consumption of the process. Hence it becomes important to share the arena allocator between sessions.
- Create and register a shared allocator with the env using the
CreateAndRegisterAllocatorAPI. This allocator is then reused by all sessions that use the same env instance unless a session chooses to override this by setting
session.use_env_allocatorsto “1” for each session that wants to use the env registered allocators.
- See test
TestSharedAllocatorUsingCreateAndRegisterAllocatorin https://github.com/microsoft/onnxruntime/blob/master/onnxruntime/test/shared_lib/test_inference.cc for an example.
- Configuring OrtArenaCfg:
- Default values for these configs can be found in the BFCArena class.
initial_chunk_size_bytes: This is the size of the region that the arena allocates first. Chunks are handed over to allocation requests from this region. If the logs show that the arena is getting extended a lot more than expected, you’re better off choosing a big enough initial size for this.
max_mem: This is the maximum amount of memory the arena allocates. If a chunk cannot be serviced by any existing region, the arena extends itself by allocating one more region depending on available memory (max_mem - allocated_so_far). An error is returned if available memory is less than the requested extension.
arena_extend_strategy: This can take only 2 values currently: kSameAsRequested or kNextPowerOfTwo. As the name suggests kNextPowerOfTwo (the default) extends the arena by a power of 2, while kSameAsRequested extends by a size that is the same as the allocation request each time. kSameAsRequested is suited for more advanced configurations where you know the expected memory usage in advance.
max_dead_bytes_per_chunk: This controls whether a chunk is split to service an allocation request. Currently if the difference between the chunk size and requested size is less than this value, the chunk is not split. This has the potential to waste memory by keeping a part of the chunk unused (hence called dead bytes) throughout the process thereby increasing the memory usage (until this chunk is returned to the arena).
- Create and register a shared allocator with the env using the
- Share initializer(s) between sessions:
- Description: This feature allows a user to share the same instance of an initializer across +multiple sessions.
- Scenario: You’ve several models that use the same set of initializers except the last few layers of the model and you load these models in the same process. When every model (session) creates a separate instance of the same initializer, it leads to excessive and wasteful memory usage since in this case it’s the same initializer. You want to optimize memory usage while having the flexibility to allocate the initializers (possibly even store them in shared memory).
- Example Usage: Use the
AddInitializerAPI to add a pre-allocated initializer to session options before calling
CreateSession. Use the same instance of session options to create several sessions allowing the initializer(s) to be shared between the sessions. See C API sample usage (TestSharingOfInitializer) and C# API sample usage (TestWeightSharingBetweenSessions).
- Include onnxruntime_c_api.h.
- Call OrtCreateEnv
- Create Session: OrtCreateSession(env, model_uri, nullptr,…)
- Optionally add more execution providers (e.g. for CUDA use OrtSessionOptionsAppendExecutionProvider_CUDA)
- Create Tensor 1) OrtCreateMemoryInfo 2) OrtCreateTensorWithDataAsOrtValue
The example below shows a sample run using the SqueezeNet model from ONNX model zoo, including dynamically reading model inputs, outputs, shape and type information, as well as running a sample vector and fetching the resulting class probabilities for inspection.
This is an important article on how Windows finds supporting dlls: Dynamic Link Library Search Order.
There are some cases where the app is not directly consuming the onnxruntime but instead calling into a DLL that is consuming the onnxruntime. People building these DLLs that consume the onnxruntime need to take care about folder structures. Do not modify the system %path% variable to add your folders. This can conflict with other software on the machine that is also using the onnxruntme. Instead place your DLL and the onnxruntime DLL in the same folder and use run-time dynamic linking to bind explicitly to that copy. You can use code like this sample does in GetModulePath() to find out what folder your dll is loaded from.