Mobilenet output with RKNN is incorrect. What is the problem?

Dear all,

I tested RKNN with Mobilenet by comparing outputs by RKNN and onnxruntime on TB-96AIoT.
But the test failed and I am thinking the board does not work correctly, but I would appreciate to you if you tell me my fault.

The step is as below:

  1. Prepare jpg image (I used one from ImageNet dataset) and onnx model.

  2. Run inference with onnxruntime. Argmax of the model output is 65. The code is as below:

#!/usr/bin/env python3

import os
import cv2
import numpy as np
import onnxruntime

def print_model_summary(onnx_sess):
    print("[Model Summary]")
    print("Inputs:")
    for i in onnx_sess.get_inputs():
        print(i)
    print("Outputs:")
    for i in onnx_sess.get_outputs():
        print(i)
    print("")


def gen_input():
    jpg = "ILSVRC2012_val_00000001.JPEG"
    img = cv2.imread(jpg)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    x = img
    x = x.astype(np.float32)
    x = (x/255.0 - (0.485, 0.456, 0.406)) / (0.229, 0.224, 0.225)
    x = np.transpose(x, (2, 0, 1))
    x = np.expand_dims(x, axis=0)
    x = x.astype(np.float32)
    return (x, os.path.basename(jpg))


def main():
    onnx_file = "mobilenetv2-7.onnx"
    sess = onnxruntime.InferenceSession(onnx_file)
    print_model_summary(sess)

    x, jpg = gen_input()
    print("Process {}".format(jpg))
    x = x.astype(np.float32)
    result = sess.run(["mobilenetv20_output_flatten0_reshape0"],
                      {"data": x})[0].astype(np.float32)
    print("Argmax: {}".format(result.argmax()))

if __name__ == "__main__":
    main()
  1. Convert ONNX model to RKNN model (mobilenetv2-7.rknn) with rknn-toolkit and below script:
#!/usr/bin/env python3

import sys
from rknn.api import RKNN


def main(onnx_path):
    # Create RKNN object
    rknn = RKNN()
    ret = rknn.load_onnx(model=onnx_path)
    if ret != 0:
        raise 'Loading ' + onnx_path + ' failed!'

    channel_mean_value="#".join(["0 0 0 1"])
    ret = rknn.config(batch_size=1,
                      channel_mean_value=channel_mean_value,
                      target_platform=['rk1808'])
    if ret != 0:
        raise 'Configuring RKNN failed!'

    ret = rknn.build(do_quantization=False)
    if ret != 0:
        raise 'Building RKNN model failed!'

    ret = rknn.export_rknn(onnx_path.replace('.onnx', '.rknn'))
    if ret != 0:
        raise 'Exporting RKNN model failed!'


if __name__ == "__main__":
    main(sys.argv[1])
  1. Apply the below patch to RKNPUTools and build rknn_mobilenet.
diff --git a/rknn-api/Linux/rknn_api_sdk/rknn_mobilenet.cpp b/rknn-api/Linux/rknn_api_sdk/rknn_mobilenet.cpp
index 7a2b178..f323ed1 100755
--- a/rknn-api/Linux/rknn_api_sdk/rknn_mobilenet.cpp
+++ b/rknn-api/Linux/rknn_api_sdk/rknn_mobilenet.cpp
@@ -73,10 +73,21 @@ int ReadLabelsFile(const string& file_name,
   return 0;
 }
 
+static float input_buf[224*224*3];
+int uint82float_input(const uint8_t *src, float *dst, size_t n_pixels,
+        const std::tuple<float, float, float> &mean,
+        const std::tuple<float, float, float> &std) {
+    for (size_t i = 0; i < n_pixels; i++) {
+        dst[3*i + 0] = ((float)src[3*i + 0]/255.0f - std::get<0>(mean)) / std::get<0>(std);
+        dst[3*i + 1] = ((float)src[3*i + 1]/255.0f - std::get<1>(mean)) / std::get<1>(std);
+        dst[3*i + 2] = ((float)src[3*i + 2]/255.0f - std::get<2>(mean)) / std::get<2>(std);
+    }
+}
+
 int main(int argc, char** argv)
 {
     const char *img_path = "/tmp/dog.jpg";
-    const char *model_path = "/tmp/mobilenet_v1-tf.rknn";
+    const char *model_path = "/tmp/mobilenetv2-7.rknn";
     const char *lable_path = "/tmp/labels.txt";
     const int output_elems = 1001;
 
@@ -88,9 +99,9 @@ int main(int argc, char** argv)
     const int output_index = 0;     // node name "MobilenetV1/Predictions/Reshape_1"
 
     // Load image
-    cv::Mat img = cv::imread(img_path, 1);
+    cv::Mat img = cv::imread(img_path);
     if(!img.data) {
-        printf("cv::imread %s fail!\n", img_path);
+        printf("cv::imread %s fail!: %s\n", img_path, strerror(errno));
         return -1;
     }
     if(img.cols != img_width || img.rows != img_height)
@@ -102,7 +113,7 @@ int main(int argc, char** argv)
     // Load model
     FILE *fp = fopen(model_path, "rb");
     if(fp == NULL) {
-        printf("fopen %s fail!\n", model_path);
+        printf("fopen %s fail!: %s\n", model_path, strerror(errno));
         return -1;
     }
     fseek(fp, 0, SEEK_END);
@@ -110,7 +121,7 @@ int main(int argc, char** argv)
     void *model = malloc(model_len);
     fseek(fp, 0, SEEK_SET);
     if(model_len != fread(model, 1, model_len, fp)) {
-        printf("fread %s fail!\n", model_path);
+        printf("fread %s fail!: %s\n", model_path, strerror(errno));
         free(model);
         return -1;
     }
@@ -136,8 +147,11 @@ int main(int argc, char** argv)
         goto Error;
     }
 
+    assert(img_width == 224);
+    assert(img_height == 224);
+    uint82float_input(img.data, input_buf, 224*224, std::make_tuple(0.485f, 0.456f, 0.406f), std::make_tuple(0.229f, 0.224f, 0.225f));
     inputs[0].index = input_index;
-    inputs[0].buf = img.data;
+    inputs[0].buf = input_buf;
     inputs[0].size = img_width * img_height * img_channels;
     inputs[0].pass_through = false;
     inputs[0].type = RKNN_TENSOR_UINT8;
  1. Copy the jpg image, rknn model and rknn_mobilenet in appropriate directory on TB-96AIoT. and run it.

After the execution I got the below output (The performance related is not pasted here) and found it does not work as expected:

D RKNNAPI: ==============================================
D RKNNAPI: RKNN VERSION:
D RKNNAPI:   API: 1.3.0 (c5654ea build: 2019-12-25 14:12:00)
D RKNNAPI:   DRV: 1.3.1 (6ebb4d7 build: 2020-01-02 09:37:58)
D RKNNAPI: ==============================================
-nan: 1000 toilet tissue
230.125: 862 toilet seat
220.5: 470 caldron
197.875: 626 lifeboat
185.125: 556 fire engine

Is there something wrong on my steps?

Thank you.

p.s.

Branch ID is here:
RKNPUTools 9ecccf4123054ad23823f1ed7c2ba6e8ea65ed96
rknn-toolkit 6c017fdb6f6264116781058d8bf0a093e796832a