mv_inference: Add MLAPI backend support 93/235493/2 tizen_ACR_MLAPI
authorInki Dae <inki.dae@samsung.com>
Fri, 5 Jun 2020 04:56:08 +0000 (13:56 +0900)
committerInki Dae <inki.dae@samsung.com>
Tue, 9 Jun 2020 01:00:12 +0000 (10:00 +0900)
This patch adds ML Single API support to MediaVision framework.

On MediaVision, Vivante NPU, SRNPU and ONE will be controlled by
inference-engine-mlapi backend which interfaces with
ML Single API of NNStreamer.

Change-Id: I89480f68a885c6ff0da13a46bc54eba6973a1431
Signed-off-by: Inki Dae <inki.dae@samsung.com>
include/mv_inference_type.h
mv_inference/inference/src/Inference.cpp
test/testsuites/inference/inference_test_suite.c

index 41a9e9dea1955de1f6f4e61571791500d9062163..29976827096917a847b10b2c71827147d1a3e494 100644 (file)
@@ -44,6 +44,8 @@ typedef enum {
     MV_INFERENCE_BACKEND_OPENCV,    /**< OpenCV */
     MV_INFERENCE_BACKEND_TFLITE,    /**< TensorFlow-Lite */
     MV_INFERENCE_BACKEND_ARMNN,     /**< ARMNN (Since 6.0) */
+    MV_INFERENCE_BACKEND_MLAPI,            /**< ML Single API of NNStreamer (Since 6.0) */
+    MV_INFERENCE_BACKEND_ONE,       /**< On-device Neural Engine (Since 6.0) */
     MV_INFERENCE_BACKEND_MAX        /**< Backend MAX */
 } mv_inference_backend_type_e;
 
index 5a12b350ce5eb509ebef856e1b55673e587c0a6a..f3d0d0d2efeb0fd7fcff9f130688bad51dc87b85 100755 (executable)
@@ -83,6 +83,8 @@ Inference::Inference() :
        mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_OPENCV, std::make_pair("opencv", false)));
        mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_TFLITE, std::make_pair("tflite", false)));
        mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_ARMNN, std::make_pair("armnn", false)));
+       mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_MLAPI, std::make_pair("mlapi", false)));
+       mSupportedInferenceBackend.insert(std::make_pair(MV_INFERENCE_BACKEND_ONE, std::make_pair("mlapi", false)));
 
        CheckSupportedInferenceBackend();
 
@@ -98,6 +100,7 @@ Inference::Inference() :
        mModelFormats.insert(std::make_pair<std::string, int>("weights", INFERENCE_MODEL_DARKNET));
        mModelFormats.insert(std::make_pair<std::string, int>("bin", INFERENCE_MODEL_DLDT));
        mModelFormats.insert(std::make_pair<std::string, int>("onnx", INFERENCE_MODEL_ONNX));
+       mModelFormats.insert(std::make_pair<std::string, int>("nb", INFERENCE_MODEL_VIVANTE));
 
        LOGI("LEAVE");
 }
@@ -288,7 +291,7 @@ int Inference::Preprocess(cv::Mat cvImg, cv::Mat cvDst, int data_type)
 
     cv::subtract(sampleFloat, meanMat, sampleNormalized);
 
-    sampleNormalized /= (float)mDeviation;
+    sampleNormalized /= static_cast<float>(mDeviation);
 
     sampleNormalized.convertTo(cvDst, data_type);
 
@@ -357,7 +360,7 @@ void Inference::ConfigureInputInfo(int width,
        mConfig.mTensorInfo = {width, height, dim, ch};
        mConfig.mStdValue = stdValue;
        mConfig.mMeanValue = meanValue;
-       mConfig.mDataType = (mv_inference_data_type_e)dataType;
+       mConfig.mDataType = static_cast<mv_inference_data_type_e>(dataType);
        mConfig.mInputLayerNames = names;
 
        inference_engine_layer_property property;
@@ -500,9 +503,9 @@ void Inference::CleanupTensorBuffers(void)
                        }
 
                        if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32)
-                               delete[] (float *)tensor_buffer.buffer;
+                               delete[] static_cast<float *>(tensor_buffer.buffer);
                        else
-                               delete[] (unsigned char *)tensor_buffer.buffer;
+                               delete[] static_cast<unsigned char *>(tensor_buffer.buffer);
                }
 
                LOGI("input tensor buffers(%zu) have been released.", mInputTensorBuffers.size());
@@ -521,9 +524,9 @@ void Inference::CleanupTensorBuffers(void)
                        }
 
                        if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32)
-                               delete[] (float *)tensor_buffer.buffer;
+                               delete[] static_cast<float *>(tensor_buffer.buffer);
                        else
-                               delete[] (unsigned char *)tensor_buffer.buffer;
+                               delete[] static_cast<unsigned char *>(tensor_buffer.buffer);
                }
 
                LOGI("output tensor buffers(%zu) have been released.", mOutputTensorBuffers.size());
@@ -571,10 +574,13 @@ int Inference::PrepareTenosrBuffers(void)
                        inference_engine_tensor_info tensor_info = mInputLayerProperty.tensor_infos[i];
                        inference_engine_tensor_buffer tensor_buffer;
                        if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) {
-                               tensor_buffer.buffer = (void *)(new float[tensor_info.size]);
+                               tensor_buffer.buffer = new float[tensor_info.size];
                                tensor_buffer.size = tensor_info.size * 4;
                        } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) {
-                               tensor_buffer.buffer = (void *)(new unsigned char[tensor_info.size]);
+                               tensor_buffer.buffer = new unsigned char[tensor_info.size];
+                               tensor_buffer.size = tensor_info.size;
+                       } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) {
+                               tensor_buffer.buffer = new short[tensor_info.size];
                                tensor_buffer.size = tensor_info.size;
                        } else {
                                LOGE("Invalid input tensor data type.");
@@ -620,6 +626,9 @@ int Inference::PrepareTenosrBuffers(void)
                        } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) {
                                tensor_buffer.buffer = new char[tensor_info.size];
                                tensor_buffer.size = tensor_info.size;
+                       } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) {
+                               tensor_buffer.buffer = new short[tensor_info.size];
+                               tensor_buffer.size = tensor_info.size;
                        } else {
                                LOGE("Invalid output tensor data type.");
                                CleanupTensorBuffers();
@@ -651,7 +660,7 @@ int Inference::FillOutputResult(tensor_t &outputData)
                inference_engine_tensor_info tensor_info = mOutputLayerProperty.tensor_infos[i];
 
                std::vector<int> tmpDimInfo;
-               for (int i = 0; i < (int)tensor_info.shape.size(); i++) {
+               for (int i = 0; i < static_cast<int>(tensor_info.shape.size()); i++) {
                        tmpDimInfo.push_back(tensor_info.shape[i]);
                }
 
@@ -659,23 +668,46 @@ int Inference::FillOutputResult(tensor_t &outputData)
 
                // Normalize output tensor data converting it to float type in case of quantized model.
                if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) {
-                       unsigned char *ori_buf = (unsigned char *)mOutputTensorBuffers[i].buffer;
                        float *new_buf = new float[tensor_info.size];
                        if (new_buf == NULL) {
                                LOGE("Fail to allocate a new output tensor buffer.");
                                return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
                        }
 
+                       unsigned char *ori_buf = static_cast<unsigned char *>(mOutputTensorBuffers[i].buffer);
+
                        for (int j = 0; j < tensor_info.size; j++) {
-                               new_buf[j] = (float)ori_buf[j] / 255.0f;
+                               new_buf[j] = static_cast<float>(ori_buf[j]) / 255.0f;
                        }
 
                        // replace original buffer with new one, and release origin one.
                        mOutputTensorBuffers[i].buffer = new_buf;
-                       delete[] ori_buf;
+
+                       if (!mOutputTensorBuffers[i].owner_is_backend)
+                               delete[] ori_buf;
                }
 
-               outputData.data.push_back((void *)mOutputTensorBuffers[i].buffer);
+               if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT16) {
+                       float *new_buf = new float[tensor_info.size];
+                       if (new_buf == NULL) {
+                               LOGE("Fail to allocate a new output tensor buffer.");
+                               return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+                       }
+
+                       short *ori_buf = static_cast<short *>(mOutputTensorBuffers[i].buffer);
+
+                       for (int j = 0; j < tensor_info.size; j++) {
+                               new_buf[j] = static_cast<float>(ori_buf[j]);
+                       }
+
+                       // replace original buffer with new one, and release origin one.
+                       mOutputTensorBuffers[i].buffer = new_buf;
+
+                       if (!mOutputTensorBuffers[i].owner_is_backend)
+                               delete[] ori_buf;
+               }
+
+               outputData.data.push_back(static_cast<void *>(mOutputTensorBuffers[i].buffer));
        }
 
        return MEDIA_VISION_ERROR_NONE;
@@ -697,6 +729,7 @@ int Inference::Bind(void)
 
        inference_engine_config config = {
                .backend_name = backendName,
+               .backend_type = mConfig.mBackedType,
                // As a default, Target device is CPU. If user defined desired device type in json file
                // then the device type will be set by Load callback.
                .target_devices = mConfig.mTargetTypes,
@@ -806,7 +839,7 @@ int Inference::Load(void)
 
        std::vector<std::string> models;
 
-       inference_model_format_e model_format = (inference_model_format_e)key->second;
+       inference_model_format_e model_format = static_cast<inference_model_format_e>(key->second);
 
        // Push model file information to models vector properly according to detected model format.
        switch (model_format) {
@@ -815,6 +848,7 @@ int Inference::Load(void)
        case INFERENCE_MODEL_DARKNET:
        case INFERENCE_MODEL_DLDT:
        case INFERENCE_MODEL_ONNX:
+       case INFERENCE_MODEL_VIVANTE:
                models.push_back(mConfig.mWeightFilePath);
                models.push_back(mConfig.mConfigFilePath);
                break;
@@ -1036,7 +1070,7 @@ int Inference::GetObjectDetectionResults(ObjectDetectionResults *detectionResult
                // indicats the image id. But it is useless if a batch mode isn't supported.
                // So, use the 1st of 7.
 
-               number_of_detections = (int)(*reinterpret_cast<float*>(outputData.data[0]));
+               number_of_detections = static_cast<int>(*reinterpret_cast<float*>(outputData.data[0]));
                cv::Mat cvOutputData(number_of_detections, inferDimInfo[0][3], CV_32F, outputData.data[0]);
 
                // boxes
@@ -1077,23 +1111,23 @@ int Inference::GetObjectDetectionResults(ObjectDetectionResults *detectionResult
                if (scores[idx] < mThreshold)
                        continue;
 
-               left =   (int)(boxes[idx*4 + 1] * mSourceSize.width);
-               top  =   (int)(boxes[idx*4 + 0] * mSourceSize.height);
-               right  = (int)(boxes[idx*4 + 3] * mSourceSize.width);
-               bottom = (int)(boxes[idx*4 + 2] * mSourceSize.height);
+               left =   static_cast<int>(boxes[idx*4 + 1] * mSourceSize.width);
+               top  =   static_cast<int>(boxes[idx*4 + 0] * mSourceSize.height);
+               right  = static_cast<int>(boxes[idx*4 + 3] * mSourceSize.width);
+               bottom = static_cast<int>(boxes[idx*4 + 2] * mSourceSize.height);
 
                loc.x = left;
                loc.y = top;
                loc.width = right -left + 1;
                loc.height = bottom - top + 1;
 
-               results.indices.push_back((int)classes[idx]);
+               results.indices.push_back(static_cast<int>(classes[idx]));
                results.confidences.push_back(scores[idx]);
-               results.names.push_back(mUserListName[(int)classes[idx]]);
+               results.names.push_back(mUserListName[static_cast<int>(classes[idx])]);
                results.locations.push_back(loc);
                results.number_of_objects++;
 
-               LOGI("objectClass: %d", (int)classes[idx]);
+               LOGI("objectClass: %d", static_cast<int>(classes[idx]));
                LOGI("confidence:%f", scores[idx]);
                LOGI("left:%d, top:%d, right:%d, bottom:%d", left, top, right, bottom);
        }
@@ -1137,7 +1171,7 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults)
                // indicats the image id. But it is useless if a batch mode isn't supported.
                // So, use the 1st of 7.
 
-               number_of_detections = (int)(*reinterpret_cast<float*>(outputData.data[0]));
+               number_of_detections = static_cast<int>(*reinterpret_cast<float*>(outputData.data[0]));
                cv::Mat cvOutputData(number_of_detections, inferDimInfo[0][3], CV_32F, outputData.data[0]);
 
                // boxes
@@ -1163,7 +1197,7 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults)
                boxes = reinterpret_cast<float*>(inferResults[0]);
                classes = reinterpret_cast<float*>(inferResults[1]);
                scores = reinterpret_cast<float*>(inferResults[2]);
-               number_of_detections = (int)(*reinterpret_cast<float*>(inferResults[3]));
+               number_of_detections = static_cast<int>(*reinterpret_cast<float*>(inferResults[3]));
        }
 
        int left, top, right, bottom;
@@ -1175,10 +1209,10 @@ int Inference::GetFaceDetectionResults(FaceDetectionResults *detectionResults)
                if (scores[idx] < mThreshold)
                        continue;
 
-               left =   (int)(boxes[idx*4 + 1] * mSourceSize.width);
-               top  =   (int)(boxes[idx*4 + 0] * mSourceSize.height);
-               right  = (int)(boxes[idx*4 + 3] * mSourceSize.width);
-               bottom = (int)(boxes[idx*4 + 2] * mSourceSize.height);
+               left =   static_cast<int>(boxes[idx*4 + 1] * mSourceSize.width);
+               top  =   static_cast<int>(boxes[idx*4 + 0] * mSourceSize.height);
+               right  = static_cast<int>(boxes[idx*4 + 3] * mSourceSize.width);
+               bottom = static_cast<int>(boxes[idx*4 + 2] * mSourceSize.height);
 
                loc.x = left;
                loc.y = top;
@@ -1224,8 +1258,8 @@ int Inference::GetFacialLandMarkDetectionResults(FacialLandMarkDetectionResults
        results.number_of_landmarks = 0;
        LOGI("imgW:%d, imgH:%d", mSourceSize.width, mSourceSize.height);
        for (int idx = 0; idx < number_of_detections; idx+=2) {
-               point.x = (int)(loc[idx] * mSourceSize.width);
-               point.y = (int)(loc[idx+1] * mSourceSize.height);
+               point.x = static_cast<int>(loc[idx] * mSourceSize.width);
+               point.y = static_cast<int>(loc[idx+1] * mSourceSize.height);
 
                results.locations.push_back(point);
                results.number_of_landmarks++;
@@ -1265,8 +1299,8 @@ int Inference::GetPoseEstimationDetectionResults(PoseEstimationResults *detectio
        cv::Mat multiChannels[inferDimInfo[0][3]];
        split(reShapeTest, multiChannels);
 
-       float ratioX = (float)mSourceSize.width / (float)inferDimInfo[0][2];
-       float ratioY = (float)mSourceSize.height / (float)inferDimInfo[0][1];
+       float ratioX = static_cast<float>(mSourceSize.width) / static_cast<float>(inferDimInfo[0][2]);
+       float ratioY = static_cast<float>(mSourceSize.height) / static_cast<float>(inferDimInfo[0][1]);
 
        PoseEstimationResults results;
        results.number_of_pose_estimation = 0;
@@ -1277,10 +1311,10 @@ int Inference::GetPoseEstimationDetectionResults(PoseEstimationResults *detectio
                cv::minMaxLoc(heatMap, NULL, &score, NULL, &loc);
 
                LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, loc.x, loc.y, score);
-               LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, (int)((float)(loc.x+1) * ratioX), (int)((float)(loc.y+1) * ratioY), score);
+               LOGI("PoseIdx[%2d]: x[%2d], y[%2d], score[%.3f]", poseIdx, static_cast<int>(static_cast<float>(loc.x+1) * ratioX), static_cast<int>(static_cast<float>(loc.y+1) * ratioY), score);
 
-               loc.x = (int)((float)(loc.x+1) * ratioX);
-               loc.y = (int)((float)(loc.y+1) * ratioY);
+               loc.x = static_cast<int>(static_cast<float>(loc.x+1) * ratioX);
+               loc.y = static_cast<int>(static_cast<float>(loc.y+1) * ratioY);
                results.locations.push_back(loc);
                results.number_of_pose_estimation++;
        }
index 4c2885f7afd44cde9708b57a3867f9a4e0f86698..117612561bc293549effae040b892b1109956477 100644 (file)
 #include <limits.h>
 #include <time.h>
 
+#define ARRAY_SIZE(x)  (sizeof((x))/sizeof((x)[0]))
 #define FILE_PATH_SIZE 1024
 
 //Image Classification
 #define IC_LABEL_PATH "/usr/share/capi-media-vision/models/IC/tflite/ic_label.txt"
 #define IC_TFLITE_WEIGHT_PATH "/usr/share/capi-media-vision/models/IC/tflite/ic_tflite_model.tflite"
 
+#define IC_VIVANTE_LABEL_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_label.txt"
+#define IC_VIVANTE_WEIGHT_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_vivante_model.nb"
+#define IC_VIVANTE_CONFIG_PATH "/usr/share/capi-media-vision/models/IC/vivante/ic_vivante_model.so"
+
 #define IC_OPENCV_LABEL_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_label_squeezenet.txt"
 #define IC_OPENCV_WEIGHT_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_model_squeezenet.caffemodel"
 #define IC_OPENCV_CONFIG_CAFFE_PATH "/usr/share/capi-media-vision/models/IC/caffe/ic_caffe_model_squeezenet.prototxt"
@@ -507,7 +512,7 @@ int perform_configuration(mv_engine_config_h *engine_cfg)
     }
 
     while (sel_opt == 0) {
-        sel_opt = show_menu("Select Actions: ", options, names, 12);
+        sel_opt = show_menu("Select Actions: ", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
             err = perform_configure_set_model_config_path(handle);
@@ -727,6 +732,88 @@ int perform_armnn_mobilenetv1_config(mv_engine_config_h *engine_cfg)
     return err;
 }
 
+int perform_vivante_inceptionv3_config(mv_engine_config_h *engine_cfg)
+{
+    int err = MEDIA_VISION_ERROR_NONE;
+
+    mv_engine_config_h handle = NULL;
+    err = mv_create_engine_config(&handle);
+    if (err != MEDIA_VISION_ERROR_NONE) {
+        printf("Fail to create engine configuration handle.\n");
+        if (handle) {
+            int err2 = mv_destroy_engine_config(handle);
+            if (err2 != MEDIA_VISION_ERROR_NONE) {
+                printf("Fail to destroy engine cofniguration.\n");
+            }
+        }
+        return err;
+    }
+
+    char *inputNodeName = "input";
+    char *outputNodeName[1] = {"InceptionV3/Predictions/Peshape_1"};
+
+    mv_engine_config_set_string_attribute(handle,
+                        MV_INFERENCE_MODEL_WEIGHT_FILE_PATH,
+                        IC_VIVANTE_WEIGHT_PATH);
+
+    mv_engine_config_set_string_attribute(handle,
+                        MV_INFERENCE_MODEL_CONFIGURATION_FILE_PATH,
+                        IC_VIVANTE_CONFIG_PATH);
+
+       mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_INPUT_DATA_TYPE,
+                        MV_INFERENCE_DATA_UINT8);
+
+    mv_engine_config_set_string_attribute(handle,
+                        MV_INFERENCE_MODEL_USER_FILE_PATH,
+                        IC_VIVANTE_LABEL_PATH);
+
+    mv_engine_config_set_double_attribute(handle,
+                        MV_INFERENCE_MODEL_MEAN_VALUE,
+                        0.0);
+
+    mv_engine_config_set_double_attribute(handle,
+                        MV_INFERENCE_MODEL_STD_VALUE,
+                        1.0);
+
+    mv_engine_config_set_double_attribute(handle,
+                        MV_INFERENCE_CONFIDENCE_THRESHOLD,
+                        0.6);
+
+    mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_BACKEND_TYPE,
+                        MV_INFERENCE_BACKEND_MLAPI);
+
+    mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_TARGET_DEVICE_TYPE,
+                        MV_INFERENCE_TARGET_DEVICE_CUSTOM);
+
+    mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_INPUT_TENSOR_WIDTH,
+                        299);
+
+    mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_INPUT_TENSOR_HEIGHT,
+                        299);
+
+    mv_engine_config_set_int_attribute(handle,
+                        MV_INFERENCE_INPUT_TENSOR_CHANNELS,
+                        3);
+
+    mv_engine_config_set_string_attribute(handle,
+                        MV_INFERENCE_INPUT_NODE_NAME,
+                        inputNodeName);
+
+    mv_engine_config_set_array_string_attribute(handle,
+                        MV_INFERENCE_OUTPUT_NODE_NAMES,
+                        outputNodeName,
+                        1);
+
+
+    *engine_cfg = handle;
+    return err;
+}
+
 int perform_opencv_caffe_squeezenet_config(mv_engine_config_h *engine_cfg)
 {
     int err = MEDIA_VISION_ERROR_NONE;
@@ -815,11 +902,12 @@ int perform_image_classification()
     int err = MEDIA_VISION_ERROR_NONE;
 
     int sel_opt = 0;
-    const int options[7] = { 1, 2, 3, 4, 5, 6, 7};
-    const char *names[7] = { "Configuration",
+    const int options[8] = { 1, 2, 3, 4, 5, 6, 7, 8};
+    const char *names[8] = { "Configuration",
                              "TFLite(cpu + Mobilenet)",
                              "OpenCV(cpu + Squeezenet)",
                              "ARMNN(cpu + Mobilenet)",
+                             "Vivante(NPU + Inceptionv3)",
                              "Prepare",
                              "Run",
                              "Back"};
@@ -829,7 +917,7 @@ int perform_image_classification()
     mv_source_h mvSource = NULL;
 
     while(sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 7);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {
@@ -884,6 +972,18 @@ int perform_image_classification()
         }
             break;
         case 5:
+        {
+            // perform Vivante
+            if (engine_cfg) {
+                int err2 = mv_destroy_engine_config(engine_cfg);
+                if (err2 != MEDIA_VISION_ERROR_NONE)
+                    printf("Fail to destroy engine_cfg [err:%i]\n", err2);
+            }
+
+            err = perform_vivante_inceptionv3_config(&engine_cfg);
+        }
+            break;
+        case 6:
         {
             //create - configure - prepare
             if (infer) {
@@ -916,7 +1016,7 @@ int perform_image_classification()
             }
         }
             break;
-        case 6:
+        case 7:
         {
             if (mvSource) {
                 int err2 = mv_destroy_source(mvSource);
@@ -964,7 +1064,7 @@ int perform_image_classification()
 
         }
             break;
-        case 7:
+        case 8:
         {
             //perform destroy
             if (engine_cfg) {
@@ -1005,7 +1105,7 @@ int perform_image_classification()
         const char *names_last[2] = { "Yes", "No" };
 
         while (sel_opt == 0) {
-            sel_opt = show_menu("Run Image Classification again?: ", options_last, names_last, 2);
+            sel_opt = show_menu("Run Image Classification again?: ", options_last, names_last, ARRAY_SIZE(options_last));
             switch (sel_opt) {
             case 1:
                 do_another = 1;
@@ -1310,7 +1410,7 @@ int perform_object_detection()
     mv_source_h mvSource = NULL;
 
     while(sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 7);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {
@@ -1486,7 +1586,7 @@ int perform_object_detection()
         const char *names_last[2] = { "Yes", "No" };
 
         while (sel_opt == 0) {
-            sel_opt = show_menu("Run Object Detection again?:", options_last, names_last, 2);
+            sel_opt = show_menu("Run Object Detection again?:", options_last, names_last, ARRAY_SIZE(options_last));
             switch(sel_opt) {
             case 1:
                 do_another = 1;
@@ -1775,7 +1875,7 @@ int perform_face_detection()
     mv_source_h mvSource = NULL;
 
     while(sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 7);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {
@@ -1948,7 +2048,7 @@ int perform_face_detection()
         const char *names_last[2] = { "Yes", "No" };
 
         while (sel_opt == 0) {
-            sel_opt = show_menu("Run Face Detection again?:", options_last, names_last, 2);
+            sel_opt = show_menu("Run Face Detection again?:", options_last, names_last, ARRAY_SIZE(options_last));
             switch(sel_opt) {
             case 1:
                 do_another = 1;
@@ -2149,7 +2249,7 @@ int perform_facial_landmark_detection()
     mv_source_h mvSource = NULL;
 
     while(sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 6);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {
@@ -2308,7 +2408,7 @@ int perform_facial_landmark_detection()
         const char *names_last[2] = { "Yes", "No" };
 
         while (sel_opt == 0) {
-            sel_opt = show_menu("Run Facial Landmark Detection again?:", options_last, names_last, 2);
+            sel_opt = show_menu("Run Facial Landmark Detection again?:", options_last, names_last, ARRAY_SIZE(options_last));
             switch(sel_opt) {
             case 1:
                 do_another = 1;
@@ -2435,7 +2535,7 @@ int perform_pose_estimation_detection()
     mv_source_h mvSource = NULL;
 
     while(sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 5);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {
@@ -2574,7 +2674,7 @@ int perform_pose_estimation_detection()
         const char *names_last[2] = { "Yes", "No" };
 
         while (sel_opt == 0) {
-            sel_opt = show_menu("Run Pose Estimation Detection again?:", options_last, names_last, 2);
+            sel_opt = show_menu("Run Pose Estimation Detection again?:", options_last, names_last, ARRAY_SIZE(options_last));
             switch(sel_opt) {
             case 1:
                 do_another = 1;
@@ -2608,7 +2708,7 @@ int main()
 
     int err = MEDIA_VISION_ERROR_NONE;
     while (sel_opt == 0) {
-        sel_opt = show_menu("Select Action:", options, names, 5);
+        sel_opt = show_menu("Select Action:", options, names, ARRAY_SIZE(options));
         switch (sel_opt) {
         case 1:
         {