20#include <onnxruntime_cxx_api.h>
42 std::unique_ptr<Ort::Env>
env =
nullptr;
43 std::unique_ptr<Ort::Session>
session =
nullptr;
46 Ort::MemoryInfo
memoryInfo = Ort::MemoryInfo(
"Cpu", OrtAllocatorType::OrtDeviceAllocator, 0, OrtMemType::OrtMemTypeDefault);
47 std::unique_ptr<Ort::IoBinding>
ioBinding =
nullptr;
53 mPImplOrt = std::make_unique<OrtVariables>();
56 if (!optionsMap.contains(
"model-path")) {
57 LOG(fatal) <<
"(ORT) Model path must be contained in options map!";
60 if (!optionsMap[
"model-path"].
empty()) {
61 mModelPath = optionsMap[
"model-path"];
62 mDeviceType = (optionsMap.contains(
"device-type") ? optionsMap[
"device-type"] :
"CPU");
63 mDeviceId = (optionsMap.contains(
"device-id") ? std::stoi(optionsMap[
"device-id"]) : -1);
64 mAllocateDeviceMemory = (optionsMap.contains(
"allocate-device-memory") ? std::stoi(optionsMap[
"allocate-device-memory"]) : 0);
65 mIntraOpNumThreads = (optionsMap.contains(
"intra-op-num-threads") ? std::stoi(optionsMap[
"intra-op-num-threads"]) : 0);
66 mInterOpNumThreads = (optionsMap.contains(
"inter-op-num-threads") ? std::stoi(optionsMap[
"inter-op-num-threads"]) : 0);
67 mLoggingLevel = (optionsMap.contains(
"logging-level") ? std::stoi(optionsMap[
"logging-level"]) : 0);
68 mEnableProfiling = (optionsMap.contains(
"enable-profiling") ? std::stoi(optionsMap[
"enable-profiling"]) : 0);
69 mEnableOptimizations = (optionsMap.contains(
"enable-optimizations") ? std::stoi(optionsMap[
"enable-optimizations"]) : 0);
70 mEnvName = (optionsMap.contains(
"onnx-environment-name") ? optionsMap[
"onnx-environment-name"] :
"onnx_model_inference");
71 mDeterministicMode = (optionsMap.contains(
"deterministic-compute") ? std::stoi(optionsMap[
"deterministic-compute"]) : 0);
73 if (mDeviceType ==
"CPU") {
74 (mPImplOrt->sessionOptions).SetIntraOpNumThreads(mIntraOpNumThreads);
75 (mPImplOrt->sessionOptions).SetInterOpNumThreads(mInterOpNumThreads);
76 if (mIntraOpNumThreads > 1 || mInterOpNumThreads > 1) {
77 (mPImplOrt->sessionOptions).SetExecutionMode(ExecutionMode::ORT_PARALLEL);
78 }
else if (mIntraOpNumThreads == 1) {
79 (mPImplOrt->sessionOptions).SetExecutionMode(ExecutionMode::ORT_SEQUENTIAL);
81 if (mLoggingLevel < 2) {
82 LOG(info) <<
"(ORT) CPU execution provider set with " << mIntraOpNumThreads <<
" (mIntraOpNumThreads) and " << mInterOpNumThreads <<
" (mInterOpNumThreads) threads";
89 (mPImplOrt->sessionOptions).DisableMemPattern();
90 (mPImplOrt->sessionOptions).DisableCpuMemArena();
92 if (mEnableProfiling) {
93 if (optionsMap.contains(
"profiling-output-path")) {
94 (mPImplOrt->sessionOptions).EnableProfiling((optionsMap[
"profiling-output-path"] +
"/ORT_LOG_").c_str());
96 LOG(warning) <<
"(ORT) If profiling is enabled, optionsMap[\"profiling-output-path\"] should be set. Disabling profiling for now.";
97 (mPImplOrt->sessionOptions).DisableProfiling();
100 (mPImplOrt->sessionOptions).DisableProfiling();
103 if (mDeterministicMode > 0) {
104 (mPImplOrt->sessionOptions).AddConfigEntry(
"session_options.use_deterministic_compute",
"1");
107 (mPImplOrt->sessionOptions).SetGraphOptimizationLevel(GraphOptimizationLevel(mEnableOptimizations));
108 (mPImplOrt->sessionOptions).SetLogSeverityLevel(OrtLoggingLevel(mLoggingLevel));
112 LOG(fatal) <<
"(ORT) Model path cannot be empty!";
118 mPImplOrt->env = std::make_unique<Ort::Env>(
119 OrtLoggingLevel(mLoggingLevel),
120 (mEnvName.empty() ?
"ORT" : mEnvName.c_str()),
122 [](
void*
param, OrtLoggingLevel
severity,
const char* category,
const char* logid,
const char* code_location,
const char*
message) {
123 if (
severity == ORT_LOGGING_LEVEL_VERBOSE) {
124 LOG(
debug) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
125 }
else if (
severity == ORT_LOGGING_LEVEL_INFO) {
126 LOG(info) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
127 }
else if (
severity == ORT_LOGGING_LEVEL_WARNING) {
128 LOG(warning) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
129 }
else if (
severity == ORT_LOGGING_LEVEL_ERROR) {
130 LOG(error) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
131 }
else if (
severity == ORT_LOGGING_LEVEL_FATAL) {
132 LOG(fatal) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
134 LOG(info) <<
"(ORT) [" << logid <<
"|" << category <<
"|" << code_location <<
"]: " <<
message;
138 (mPImplOrt->env)->DisableTelemetryEvents();
143 if (mAllocateDeviceMemory) {
146 mPImplOrt->sessionOptions.AddConfigEntry(
"session.load_model_format",
"ONNX");
147 mPImplOrt->sessionOptions.AddConfigEntry(
"session.use_ort_model_bytes_directly",
"1");
149 mPImplOrt->session = std::make_unique<Ort::Session>(*mPImplOrt->env,
152 mPImplOrt->sessionOptions);
153 mPImplOrt->ioBinding = std::make_unique<Ort::IoBinding>(*mPImplOrt->session);
157 if (mLoggingLevel < 2) {
158 LOG(info) <<
"(ORT) Model loaded successfully from buffer! (inputs: " << printShape(mInputShapes, mInputNames) <<
", outputs: " << printShape(mOutputShapes, mInputNames) <<
")";
164 if (mAllocateDeviceMemory) {
167 mPImplOrt->session = std::make_unique<Ort::Session>(*mPImplOrt->env, mModelPath.c_str(), mPImplOrt->sessionOptions);
168 mPImplOrt->ioBinding = std::make_unique<Ort::IoBinding>(*mPImplOrt->session);
172 if (mLoggingLevel < 2) {
173 LOG(info) <<
"(ORT) Model loaded successfully! (inputs: " << printShape(mInputShapes, mInputNames) <<
", outputs: " << printShape(mOutputShapes, mInputNames) <<
")";
179 if (deviceIndex >= 0) {
180 (mPImplOrt->runOptions).AddConfigEntry(
"disable_synchronize_execution_providers",
"1");
181 (mPImplOrt->sessionOptions).AddConfigEntry(
"session.use_device_allocator_for_initializers",
"1");
182 (mPImplOrt->sessionOptions).AddConfigEntry(
"session.use_env_allocators",
"1");
183 (mPImplOrt->sessionOptions).AddConfigEntry(
"session_options.enable_cpu_mem_arena",
"0");
186 (mPImplOrt->runOptions).AddConfigEntry(
"memory.enable_memory_arena_shrinkage", (
"gpu:" +
std::to_string(deviceIndex)).c_str());
188 std::string dev_mem_str =
"";
189 if (mDeviceType ==
"ROCM") {
190 dev_mem_str =
"HipPinned";
192 if (mDeviceType ==
"CUDA") {
193 dev_mem_str =
"Cuda";
195 mPImplOrt->memoryInfo = Ort::MemoryInfo(dev_mem_str.c_str(), OrtAllocatorType::OrtDeviceAllocator, deviceIndex, OrtMemType::OrtMemTypeDefault);
196 if (mLoggingLevel < 2) {
197 LOG(info) <<
"(ORT) Memory info set to on-device memory for device type " << mDeviceType <<
" with ID " << deviceIndex <<
" and mPImplOrt pointer " << mPImplOrt;
204 mPImplOrt->session = std::make_unique<Ort::Session>(*(mPImplOrt->env), mModelPath.c_str(), mPImplOrt->sessionOptions);
210 return &mPImplOrt->sessionOptions;
215 return &mPImplOrt->memoryInfo;
220 return (mPImplOrt->env).get();
223template <
class I,
class O>
226 if constexpr (std::is_same_v<I, O>) {
229 std::vector<O>
output(input.size());
230 std::transform(std::begin(input), std::end(input), std::begin(
output), [](I
f) {
return O(
f); });
240 for (
size_t i = 0;
i < (mPImplOrt->session)->GetInputCount(); ++
i) {
241 mInputNames.push_back((mPImplOrt->session)->GetInputNameAllocated(
i, mPImplOrt->allocator).get());
243 for (
size_t i = 0;
i < (mPImplOrt->session)->GetInputCount(); ++
i) {
244 mInputShapes.emplace_back((mPImplOrt->session)->GetInputTypeInfo(
i).GetTensorTypeAndShapeInfo().GetShape());
246 for (
size_t i = 0;
i < (mPImplOrt->session)->GetOutputCount(); ++
i) {
247 mOutputNames.push_back((mPImplOrt->session)->GetOutputNameAllocated(
i, mPImplOrt->allocator).get());
249 for (
size_t i = 0;
i < (mPImplOrt->session)->GetOutputCount(); ++
i) {
250 mOutputShapes.emplace_back((mPImplOrt->session)->GetOutputTypeInfo(
i).GetTensorTypeAndShapeInfo().GetShape());
253 mInputNamesChar.resize(mInputNames.size(),
nullptr);
254 std::transform(std::begin(mInputNames), std::end(mInputNames), std::begin(mInputNamesChar),
255 [&](
const std::string&
str) {
return str.c_str(); });
256 mOutputNamesChar.resize(mOutputNames.size(),
nullptr);
257 std::transform(std::begin(mOutputNames), std::end(mOutputNames), std::begin(mOutputNamesChar),
258 [&](
const std::string&
str) {
return str.c_str(); });
260 mInputShapesCopy = mInputShapes;
261 mOutputShapesCopy = mOutputShapes;
262 mInputSizePerNode.resize(mInputShapes.size(), 1);
263 mOutputSizePerNode.resize(mOutputShapes.size(), 1);
265 for (
size_t i = 0;
i < mInputShapes.size(); ++
i) {
266 if (mInputShapes[
i].
size() > 0) {
267 for (
size_t j = 1;
j < mInputShapes[
i].size(); ++
j) {
268 if (mInputShapes[
i][
j] > 0) {
269 mInputsTotal *= mInputShapes[
i][
j];
270 mInputSizePerNode[
i] *= mInputShapes[
i][
j];
276 for (
size_t i = 0;
i < mOutputShapes.size(); ++
i) {
277 if (mOutputShapes[
i].
size() > 0) {
278 for (
size_t j = 1;
j < mOutputShapes[
i].size(); ++
j) {
279 if (mOutputShapes[
i][
j] > 0) {
280 mOutputsTotal *= mOutputShapes[
i][
j];
281 mOutputSizePerNode[
i] *= mOutputShapes[
i][
j];
290 mPImplOrt->env.reset(env);
294template <
class I,
class O>
297 std::vector<int64_t> inputShape = mInputShapes[0];
298 inputShape[0] = input.size();
299 for (
size_t i = 1;
i < mInputShapes[0].size(); ++
i) {
300 inputShape[0] /= mInputShapes[0][
i];
302 std::vector<Ort::Value> inputTensor;
303 if constexpr (std::is_same_v<I, OrtDataType::Float16_t>) {
304 inputTensor.emplace_back(Ort::Value::CreateTensor<Ort::Float16_t>(mPImplOrt->memoryInfo,
reinterpret_cast<Ort::Float16_t*
>(input.data()), input.size(), inputShape.data(), inputShape.size()));
306 inputTensor.emplace_back(Ort::Value::CreateTensor<I>(mPImplOrt->memoryInfo, input.data(), input.size(), inputShape.data(), inputShape.size()));
309 auto outputTensors = (mPImplOrt->session)->Run(mPImplOrt->runOptions, mInputNamesChar.data(), inputTensor.data(), inputTensor.size(), mOutputNamesChar.data(), mOutputNamesChar.size());
310 O* outputValues = outputTensors[0].template GetTensorMutableData<O>();
311 std::vector<O> outputValuesVec{outputValues, outputValues + inputShape[0] * mOutputShapes[0][1]};
312 outputTensors.clear();
313 return outputValuesVec;
316template std::vector<float> o2::ml::OrtModel::inference<float, float>(std::vector<float>&);
317template std::vector<float> o2::ml::OrtModel::inference<OrtDataType::Float16_t, float>(std::vector<OrtDataType::Float16_t>&);
318template std::vector<OrtDataType::Float16_t> o2::ml::OrtModel::inference<OrtDataType::Float16_t, OrtDataType::Float16_t>(std::vector<OrtDataType::Float16_t>&);
320template <
class I,
class O>
327 std::vector<int64_t> inputShape{input_size, (
int64_t)mInputShapes[0][1]};
328 Ort::Value inputTensor = Ort::Value(
nullptr);
329 if constexpr (std::is_same_v<I, OrtDataType::Float16_t>) {
330 inputTensor = Ort::Value::CreateTensor<Ort::Float16_t>(mPImplOrt->memoryInfo,
reinterpret_cast<Ort::Float16_t*
>(input), input_size * mInputShapes[0][1], inputShape.data(), inputShape.size());
332 inputTensor = Ort::Value::CreateTensor<I>(mPImplOrt->memoryInfo, input, input_size * mInputShapes[0][1], inputShape.data(), inputShape.size());
334 (mPImplOrt->ioBinding)->BindInput(mInputNames[0].c_str(), inputTensor);
336 std::vector<int64_t> outputShape{input_size, mOutputShapes[0][1]};
337 Ort::Value outputTensor = Ort::Value(
nullptr);
338 if constexpr (std::is_same_v<O, OrtDataType::Float16_t>) {
339 outputTensor = Ort::Value::CreateTensor<Ort::Float16_t>(mPImplOrt->memoryInfo,
reinterpret_cast<Ort::Float16_t*
>(
output), input_size * mOutputShapes[0][1], outputShape.data(), outputShape.size());
341 outputTensor = Ort::Value::CreateTensor<O>(mPImplOrt->memoryInfo,
output, input_size * mOutputShapes[0][1], outputShape.data(), outputShape.size());
343 (mPImplOrt->ioBinding)->BindOutput(mOutputNames[0].c_str(), outputTensor);
345 (mPImplOrt->session)->Run(mPImplOrt->runOptions, *mPImplOrt->ioBinding);
356template void OrtModel::inference<OrtDataType::Float16_t, OrtDataType::Float16_t>(OrtDataType::Float16_t*,
int64_t, OrtDataType::Float16_t*);
357template void OrtModel::inference<OrtDataType::Float16_t, float>(OrtDataType::Float16_t*,
int64_t,
float*);
358template void OrtModel::inference<float, OrtDataType::Float16_t>(
float*,
int64_t, OrtDataType::Float16_t*);
359template void OrtModel::inference<float, float>(
float*,
int64_t,
float*);
361template <
class I,
class O>
364 std::vector<Ort::Value> inputTensors(mInputShapesCopy.size());
366 for (
size_t i = 0;
i < mInputShapesCopy.size(); ++
i) {
368 mInputShapesCopy[
i][0] = input_size;
369 mOutputShapesCopy[
i][0] = input_size;
371 if constexpr (std::is_same_v<I, OrtDataType::Float16_t>) {
372 inputTensors[
i] = Ort::Value::CreateTensor<Ort::Float16_t>(
373 mPImplOrt->memoryInfo,
374 reinterpret_cast<Ort::Float16_t*
>(input[
i]),
375 mInputSizePerNode[
i] * input_size,
376 mInputShapesCopy[
i].data(),
377 mInputShapesCopy[
i].size());
379 inputTensors[
i] = Ort::Value::CreateTensor<I>(
380 mPImplOrt->memoryInfo,
382 mInputSizePerNode[
i] * input_size,
383 mInputShapesCopy[
i].data(),
384 mInputShapesCopy[
i].size());
388 Ort::Value outputTensor = Ort::Value(
nullptr);
389 if constexpr (std::is_same_v<O, OrtDataType::Float16_t>) {
390 outputTensor = Ort::Value::CreateTensor<Ort::Float16_t>(
391 mPImplOrt->memoryInfo,
392 reinterpret_cast<Ort::Float16_t*
>(
output),
393 mOutputSizePerNode[0] * input_size,
394 mOutputShapesCopy[0].data(),
395 mOutputShapesCopy[0].size());
397 outputTensor = Ort::Value::CreateTensor<O>(
398 mPImplOrt->memoryInfo,
400 mOutputSizePerNode[0] * input_size,
401 mOutputShapesCopy[0].data(),
402 mOutputShapesCopy[0].size());
406 mPImplOrt->session->Run(
407 mPImplOrt->runOptions,
408 mInputNamesChar.data(),
410 mInputNamesChar.size(),
411 mOutputNamesChar.data(),
413 mOutputNamesChar.size());
416template void OrtModel::inference<OrtDataType::Float16_t, OrtDataType::Float16_t>(OrtDataType::Float16_t**,
int64_t, OrtDataType::Float16_t*);
417template void OrtModel::inference<OrtDataType::Float16_t, float>(OrtDataType::Float16_t**,
int64_t,
float*);
418template void OrtModel::inference<float, OrtDataType::Float16_t>(
float**,
int64_t, OrtDataType::Float16_t*);
419template void OrtModel::inference<float, float>(
float**,
int64_t,
float*);
421template <
class I,
class O>
424 std::vector<Ort::Value> input_tensors;
426 for (
size_t i = 0;
i < inputs.size(); ++
i) {
428 mInputShapesCopy[
i][0] = inputs[
i].size() / mInputSizePerNode[
i];
430 if constexpr (std::is_same_v<I, OrtDataType::Float16_t>) {
431 input_tensors.emplace_back(
432 Ort::Value::CreateTensor<Ort::Float16_t>(
433 mPImplOrt->memoryInfo,
434 reinterpret_cast<Ort::Float16_t*
>(inputs[
i].data()),
435 mInputSizePerNode[
i] * mInputShapesCopy[
i][0],
436 mInputShapesCopy[
i].data(),
437 mInputShapesCopy[
i].size()));
439 input_tensors.emplace_back(
440 Ort::Value::CreateTensor<I>(
441 mPImplOrt->memoryInfo,
443 mInputSizePerNode[
i] * mInputShapesCopy[
i][0],
444 mInputShapesCopy[
i].data(),
445 mInputShapesCopy[
i].size()));
449 int32_t totalOutputSize = mOutputsTotal * mInputShapesCopy[0][0];
452 auto output_tensors = mPImplOrt->session->Run(
453 mPImplOrt->runOptions,
454 mInputNamesChar.data(),
455 input_tensors.data(),
456 input_tensors.size(),
457 mOutputNamesChar.data(),
458 mOutputNamesChar.size());
461 O* output_data = output_tensors[0].template GetTensorMutableData<O>();
462 std::vector<O> output_vec(output_data, output_data + totalOutputSize);
463 output_tensors.clear();
467template std::vector<float> OrtModel::inference<float, float>(std::vector<std::vector<float>>&);
468template std::vector<OrtDataType::Float16_t> OrtModel::inference<OrtDataType::Float16_t, OrtDataType::Float16_t>(std::vector<std::vector<OrtDataType::Float16_t>>&);
477std::string OrtModel::printShape(
const std::vector<int64_t>&
v)
479 std::stringstream ss(
"");
480 for (
size_t i = 0;
i <
v.size() - 1;
i++) {
483 ss <<
v[
v.size() - 1];
487std::string OrtModel::printShape(
const std::vector<std::vector<int64_t>>&
v, std::vector<std::string>&
n)
489 std::stringstream ss(
"");
490 for (
size_t i = 0;
i <
v.size();
i++) {
491 ss <<
n[
i] <<
" -> (";
492 for (
size_t j = 0;
j <
v[
i].size() - 1;
j++) {
493 ss <<
v[
i][
j] <<
"x";
495 ss <<
v[
i][
v[
i].size() - 1] <<
"); ";
A header library for loading ONNX models and inferencing them on CPU and GPU.
void initOptions(std::unordered_map< std::string, std::string > optionsMap)
void memoryOnDevice(int32_t=0)
std::vector< O > v2v(std::vector< I > &, bool=true)
void initSessionFromBuffer(const char *buffer, size_t bufferSize)
Ort::MemoryInfo * getMemoryInfo()
std::vector< O > inference(std::vector< I > &)
void init(std::unordered_map< std::string, std::string > optionsMap)
Ort::SessionOptions * getSessionOptions()
GLuint GLsizei const GLchar * message
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Ort::RunOptions runOptions
Ort::AllocatorWithDefaultOptions allocator
Ort::MemoryInfo memoryInfo
std::unique_ptr< Ort::Session > session
ONNX session.
Ort::SessionOptions sessionOptions
std::unique_ptr< Ort::IoBinding > ioBinding
std::unique_ptr< Ort::Env > env
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"