ncnn 安卓端不同硬件平台相同系统大版本相同输入下模型推理输出不一致

k10s72fa  于 2023-03-19  发布在  其他
关注(0)|答案(2)|浏览(298)

error log | 日志或报错信息 | ログ

安卓端、不同硬件平台、相同系统大版本下:retinaface人脸检测相同Mat输入,模型推理输出不一致

context | 编译/运行环境 | バックグラウンド

Android应用开发工具:
Android Studio 3.5.2
Gradle:gradle-5.4.1-all
NDK:21.1.6352462
Cmake:3.6.4111459

ncnn:
commit id:2ef57a6204d24d3f527832cebb902f2f04df0cca
android lib build:Ubuntu 18.04/python 3.6.9/cmake 3.10.2/android-ndk-r21e

所有Android对比测试设备:
1、展锐SC9863A/Android 10.0
2、高通qcm2150/Android 10.0
3、麒麟Kirin970/Android 10.0
4、联发科天玑800U/Android 10.0

how to reproduce | 复现步骤 | 再現方法

1.编写人脸检测模型推理及日志记录代码

//读取本地图片
......
  InputStream is = getActivity().getContentResolver().openInputStream(uri);
  Bitmap mBitmap = BitmapFactory.decodeStream(is);
  mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
......
//调用人脸检测模型native方法
......
......
AndroidBitmapInfo info;
AndroidBitmap_getInfo(env, obj_bitmap, &info);
int width = info.width;
int height = info.height;
if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
  return ret;
}
ncnn::Mat ncnn_img = ncnn::Mat::from_android_bitmap(env, obj_bitmap, ncnn::Mat::PIXEL_BGR2RGB);
pretty_print_into_file(ncnn_img, "ncnn_img");//输入ncnn mat数据打印
std::vector<FaceObject> finalBbox;
int status = mDetectRetinaFace->detect_retinaface(ncnn_img, finalBbox);//人脸检测模型推理
......
int DetectRetinaFace::detect_retinaface(const ncnn::Mat &ncnn_img, std::vector<FaceObject> &faceobjects) {

        ncnn::Extractor ex = RetinaNet.create_extractor();
        ex.input(faceDetect_opt_param_id::BLOB_data, ncnn_img);
        std::vector<FaceObject> faceproposals;

        //int status1 = get_faceproposals_stride8(ex, faceproposals);
        ncnn::Mat score_blob, bbox_blob, landmark_blob;
        int status1 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride8, score_blob);
        int status2 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride8, bbox_blob);
        int status3 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride8, landmark_blob);
        //输出3节点stride8 ncnn mat数据打印
        pretty_print_into_file(score_blob, "face_detect_stride8_score_blob");
        pretty_print_into_file(bbox_blob, "face_detect_stride8_bbox_blob");
        pretty_print_into_file(landmark_blob, "face_detect_stride8_landmark_blob");

        //int status2 = get_faceproposals_stride16(ex, faceproposals);
        ncnn::Mat score_blob, bbox_blob, landmark_blob;
        int status4 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride16, score_blob);
        int status5 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride16, bbox_blob);
        int status6 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride16, landmark_blob);
        //输出3节点stride16 ncnn mat数据打印
        pretty_print_into_file(score_blob, "face_detect_stride16_score_blob");
        pretty_print_into_file(bbox_blob, "face_detect_stride16_bbox_blob");
        pretty_print_into_file(landmark_blob, "face_detect_stride16_landmark_blob");

        //int status3 = get_faceproposals_stride32(ex, faceproposals);
        ncnn::Mat score_blob, bbox_blob, landmark_blob;
        int status7 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_cls_prob_reshape_stride32, score_blob);
        int status8 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_bbox_pred_stride32, bbox_blob);
        int status9 = ex.extract(faceDetect_opt_param_id::BLOB_face_rpn_landmark_pred_stride32, landmark_blob);
        //输出3节点stride32 ncnn mat数据打印
        pretty_print_into_file(score_blob, "face_detect_stride32_score_blob");
        pretty_print_into_file(bbox_blob, "face_detect_stride32_bbox_blob");
        pretty_print_into_file(landmark_blob, "face_detect_stride32_landmark_blob");
......
}

2.挑选一张带人脸的bmp格式图片作为待测试图
3.在不同设备上运行该应用代码,并观察结果输出

more | 其他 | その他

1、四台对比设备中:模型输入完全一致,展锐与联发科的输出数据完全一致,高通与麒麟的输出比较接近(误差小于0.1%),展锐/联发科与高通/麒麟存在较大差距(误差大于1%)

2、另外还发现一个现象,就是不同Android版本(5.1/7.1/8.1/10.0)之间读取相同bmp图片后通过ncnn库接口构造的模型输入存在一定差距,即以下对象

ncnn::Mat ncnn_img = ncnn::Mat::from_android_bitmap(env, obj_bitmap, ncnn::Mat::PIXEL_BGR2RGB);
pretty_print_into_file(ncnn_img, "ncnn_img");//输入ncnn mat数据打印,不同Android大版本上运行存在差距

测试图片与模型文件详见附件
bug_test_files.zip

iih3973s

iih3973s1#

经分析,应该是不同安卓硬件平台对浮点指令集的支持存在差异,对于支持fp16的设备,ncnn会默认使用fp16精度来推理,不支持的则使用fp32来推理,所以造成了相同输入下的推理结果差异,如若保持不同硬件平台下的推理精度一致,除了需要使用bmp格式的图片数据来测试,还需要强制统一设定ncnn的精度类型,如

net.opt.use_fp16_packed = false;
net.opt.use_fp16_storage = false;
net.opt.use_fp16_arithmetic = false;

但这样做会降低性能,尤其对复杂模型来说,下降幅度较大,所以不推荐使用,最终在精度与性能之间只能做一个平衡考虑。

drnojrws

drnojrws2#

是的,faq文档中也有提到这个
https://github.com/Tencent/ncnn/wiki/FAQ-ncnn-produce-wrong-result#disable-fp16
经分析,应该是不同安卓硬件平台对浮点指令集的支持存在差异,对于支持fp16的设备,ncnn会默认使用fp16精度来推理,不支持的则使用fp32来推理,所以造成了相同输入下的推理结果差异,如若保持不同硬件平台下的推理精度一致,除了需要使用bmp格式的图片数据来测试,还需要强制统一设定ncnn的精度类型,如

net.opt.use_fp16_packed = false;
net.opt.use_fp16_storage = false;
net.opt.use_fp16_arithmetic = false;

但这样做会降低性能,尤其对复杂模型来说,下降幅度较大,所以不推荐使用,最终在精度与性能之间只能做一个平衡考虑。

相关问题