From bdf72ad5e3d30607a94b65c6690fa4749cc44551 Mon Sep 17 00:00:00 2001 From: jignparm Date: Mon, 25 Feb 2019 19:06:51 -0800 Subject: [PATCH] Update C-API with working example (#503) * Add working example of C-API * Section formatting * Shortened example, and grouped by functionality * Update C_API.md --- docs/C_API.md | 163 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 2 deletions(-) diff --git a/docs/C_API.md b/docs/C_API.md index bbaefe6188..48470053ba 100644 --- a/docs/C_API.md +++ b/docs/C_API.md @@ -11,13 +11,172 @@ * Setting the thread pool size for each session. * Dynamically loading custom ops. -## Very simplified outline of how to use it +## Usage Overview 1. Include [onnxruntime_c_api.h](/include/onnxruntime/core/session/onnxruntime_c_api.h). 2. Call OrtCreateEnv 3. Create Session: OrtCreateSession(env, model_uri, nullptr,...) 4. Create Tensor 1) OrtCreateAllocatorInfo - 2) OrtCreateTensorWithDataAsONNXValue + 2) OrtCreateTensorWithDataAsOrtValue 5. OrtRun +## Sample code + +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. + + +```c +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +// + +#include +#include +#include +#include +#include + +//***************************************************************************** +// helper function to check for status +#define CHECK_STATUS(expr) \ + do { \ + OrtStatus* onnx_status = (expr); \ + if (onnx_status != NULL) { \ + const char* msg = OrtGetErrorMessage(onnx_status); \ + fprintf(stderr, "%s\n", msg); \ + OrtReleaseStatus(onnx_status); \ + abort(); \ + } \ + } while (0); + +int main(int argc, char *argv[]) +{ + //************************************************************************* + // initialize enviroment...one enviroment per process + // enviroment maintains thread pools and other state info + OrtEnv* env; + CHECK_STATUS(OrtCreateEnv(ORT_LOGGING_LEVEL_WARNING, "test", &env)); + + // initialize session options if needed + OrtSessionOptions* session_option = OrtCreateSessionOptions(); + OrtSetSessionThreadPoolSize(session_option, 1); + + //************************************************************************* + // create session and load model into memory + // using squeezenet version 1.3 + // URL = https://github.com/onnx/models/tree/master/squeezenet + OrtSession* session; + const wchar_t * model_path = L"model.onnx"; + CHECK_STATUS(OrtCreateSession(env, model_path, session_option, &session)); + + //************************************************************************* + // print model input layer (node names, types, shape etc.) + + size_t num_inputs; + OrtStatus* status; + OrtAllocator* allocator; + OrtCreateDefaultAllocator(&allocator); + + // print number of model input nodes + status = OrtSessionGetInputCount(session, &num_inputs); + char **input_names = (char**)malloc(num_inputs * sizeof(char*)); + printf("Number of inputs = %zu\n", num_inputs); + + // iterate over all input nodes + for (int i = 0; i < num_inputs; i++) + { + // print input node names + char* input_name; + status = OrtSessionGetInputName(session, i, allocator, &input_name); + printf("Input %d : name=%s\n", i, input_name); + input_names[i] = input_name; + + // print input node types + OrtTypeInfo* typeinfo; + status = OrtSessionGetInputTypeInfo(session, i, &typeinfo); + const OrtTensorTypeAndShapeInfo* tensor_info = OrtCastTypeInfoToTensorInfo(typeinfo); + ONNXTensorElementDataType type = OrtGetTensorElementType(tensor_info); + printf("Input %d : type=%d\n", i, type); + + // print input shapes + size_t num_dims = OrtGetNumOfDimensions(tensor_info); + int64_t* dims = (int64_t*)malloc(num_dims * sizeof(int64_t)); + + printf("Input %d : num_dims=%zu\n", i, num_dims); + + OrtGetDimensions(tensor_info, dims, num_dims); + + for (int j = 0; j < num_dims; j++) + printf("Input %d : dim %d=%jd\n", i, j, dims[j]); + + OrtReleaseTypeInfo(typeinfo); + } + OrtReleaseAllocator(allocator); + + // Results should be... + // Number of inputs = 1 + // Input 0 : name = data_0 + // Input 0 : type = 1 + // Input 0 : num_dims = 4 + // Input 0 : dim 0 = 1 + // Input 0 : dim 1 = 3 + // Input 0 : dim 2 = 224 + // Input 0 : dim 3 = 224 + + //************************************************************************* + // Similar operations to get output node information. + // Use OrtSessionGetOutputCount(), OrtSessionGetOutputName() + // OrtSessionGetOutputTypeInfo() as shown above. + + //************************************************************************* + // Score the model using sample data, and inspect values + + size_t input_dims[] = { 1, 3, 224, 224 }; + size_t input_count = 3 * 224 * 224; // input tensor count = product of dims + float* input_data = (float *) malloc(sizeof(float) * input_count); + const char* output_names[] = { "softmaxout_1"}; + + // initialize input data with values in [0.0, 1.0] + for (unsigned int i = 0; i < input_count; i++) + input_data[i] = (float)i / (float)(input_count + 1); + + // create input tensor object from data values + OrtAllocatorInfo* allocator_info; + CHECK_STATUS(OrtCreateCpuAllocatorInfo(OrtArenaAllocator, OrtMemTypeDefault, &allocator_info)); + OrtValue* input_tensor = NULL; + CHECK_STATUS(OrtCreateTensorWithDataAsOrtValue(allocator_info, input_data, input_count * sizeof(float), input_dims, 4, ONNX_TENSOR_ELEMENT_DATA_TYPE_FLOAT, &input_tensor)); + assert(OrtIsTensor(input_tensor)); + OrtReleaseAllocatorInfo(allocator_info); + + // score model & input tensor, get back output tensor + OrtValue* output_tensor = NULL; + CHECK_STATUS(OrtRun(session, NULL, input_names, (const OrtValue* const*)&input_tensor, 1, output_names, 1, &output_tensor)); + assert(OrtIsTensor(output_tensor)); + + // copy output tensor values to float array + // model produces scores for 1000 classes + float* floatarr = (float *) malloc(1000 * sizeof(float)); + OrtGetTensorMutableData(output_tensor, (void **) &floatarr); + + // score the model, and print scores for first 5 classes + for (int i = 0; i < 5; i++) + printf("Score for class [%d] = %f\n", i, floatarr[i]); + + // Results should be as below... + // Score for class[0] = 0.000045 + // Score for class[1] = 0.003846 + // Score for class[2] = 0.000125 + // Score for class[3] = 0.001180 + // Score for class[4] = 0.001317 + + free(input_data); + OrtReleaseValue(output_tensor); + OrtReleaseValue(input_tensor); + OrtReleaseEnv(env); + printf("Done!\n"); + return 0; +} + + +